> For the complete documentation index, see [llms.txt](https://boxlang.ortusbooks.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://boxlang.ortusbooks.com/boxlang-framework/modularity/jwt/security-best-practices.md).

# Security Best Practices

JWTs are easy to use but easy to misuse. This page collects the production hardening guidance specific to `bx-jwt` — most are one-line configuration changes.

## 1. Reject `alg:none` (Built-in)

`bx-jwt` **unconditionally rejects** unsigned (`alg:none`) tokens. There is no setting to disable this. Any attempt to verify or refresh such a token throws `bxjwt.JWTVerificationException`.

## 2. Lock Down the Algorithm Allowlist

Algorithm-confusion attacks rely on the verifier accepting an algorithm the issuer never intended (the classic example is asking an RSA verifier to treat a public key as an HMAC secret). Cut the attack off by enumerating exactly the algorithms you expect:

```javascript
// ModuleConfig.bx
allowedAlgorithms = [ "HS256", "RS256" ]
```

Any token signed with anything else throws `JWTVerificationException`. Leaving the array empty allows every algorithm the module supports — fine for prototypes, not for production.

## 3. Use Compliant HMAC Key Sizes

RFC 7518 §3.2 defines minimum HMAC key lengths and `bx-jwt` enforces them at parse time:

| Algorithm | Minimum             |
| --------- | ------------------- |
| `HS256`   | 32 bytes (256 bits) |
| `HS384`   | 48 bytes (384 bits) |
| `HS512`   | 64 bytes (512 bits) |

Use [`jwtGenerateSecret( bits )`](/boxlang-framework/modularity/jwt/reference/built-in-functions/jwtgeneratesecret.md) to always produce a compliant key. Hand-typed strings almost always fail this check.

## 4. Tune Clock Skew Per Environment

`clockSkew` (default: 60 seconds) absorbs drift between distributed services without opening a large vulnerability window. Tune it down for security-sensitive flows, up for far-flung clusters:

```javascript
// Strict: zero tolerance — best for short-lived tokens
payload = jwtVerify( token, secret, "HS256", { clockSkew: 0 } );

// Looser: 2 minutes — for hostile WAN environments
payload = jwtVerify( token, secret, "HS256", { clockSkew: 120 } );
```

## 5. Always Assert Issuer / Audience

A token signed by `auth-service` for the `analytics` audience should not authenticate against the `payments` API. Pin both:

```javascript
payload = jwtVerify( token, key, "HS256", {
    claims: { iss: "auth-service", aud: "payments" }
} );
```

Or set `defaultIssuer` / `defaultAudience` in `ModuleConfig.bx` so they are auto-injected on issue.

## 6. Keep Lifetimes Short

* Short-lived access tokens (minutes to \~1 hour) limit the blast radius of theft.
* Pair with a refresh flow using [`jwtRefresh()`](/boxlang-framework/modularity/jwt/reference/built-in-functions/jwtrefresh.md) and `allowExpired: true` for graceful renewal.
* Always set `exp` — either explicitly in the payload, with `.expireIn()` on the builder, or via the `defaultExpiration` setting.

## 7. Stamp `kid` and Verify Through It

For any deployment that may rotate keys (i.e. all of them), stamp a `kid` header on every signed token and look the key up at verify time. See [Key Rotation](/boxlang-framework/modularity/jwt/key-rotation.md) for the full pattern.

## 8. Never Trust `jwtDecode()` Output

`jwtDecode()` is read-only — it does not verify signatures. Use it to pick a `kid` or detect the `alg`, then always follow up with `jwtVerify()` before acting on any claim.

## 9. Encrypt PII / PHI With JWE

For payloads containing sensitive personal data, use [JWE](/boxlang-framework/modularity/jwt/encryption-jwe.md) instead of (or in addition to) JWS. For both integrity and confidentiality, sign first then encrypt — the [nested JWT pattern](/boxlang-framework/modularity/jwt/encryption-jwe.md#nested-jwt-sign-encrypt).

## 10. Store Keys Outside the Codebase

Use the [`keys` registry](/boxlang-framework/modularity/jwt/key-management.md) with `${env.VAR}` substitution, or load keys from a KMS / Vault at runtime via `JWTService.registerKey()`. Keys committed to source control should be considered compromised.

## Quick Checklist

* [ ] `allowedAlgorithms` set
* [ ] HMAC secrets generated by `jwtGenerateSecret()`
* [ ] `clockSkew` tuned to environment
* [ ] `iss` and `aud` asserted on verify
* [ ] All tokens have an `exp`
* [ ] `kid` stamped on every issued token
* [ ] Keys sourced from env / KMS, never hardcoded
* [ ] Sensitive payloads encrypted (JWE), not just signed

## Related

* [Configuration](/boxlang-framework/modularity/jwt/configuration.md)
* [Key Management](/boxlang-framework/modularity/jwt/key-management.md)
* [Key Rotation](/boxlang-framework/modularity/jwt/key-rotation.md)
* [Algorithms](/boxlang-framework/modularity/jwt/reference/algorithms.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://boxlang.ortusbooks.com/boxlang-framework/modularity/jwt/security-best-practices.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
