JWT Security Tips
Hardening JSON Web Tokens in production — algorithms, lifetimes, storage, and revocation patterns.
1. Pin the Algorithm
Never trust the alg header from the client. Always enforce a single algorithm server-side — prefer RS256 or ES256 over symmetric HMAC when multiple services consume the token.
2. Short Lifetimes + Refresh
Access tokens should live 5–15 minutes. Pair them with opaque refresh tokens stored in an HttpOnly, Secure, SameSite=Strict cookie. Rotate the refresh token on every use and revoke the previous one.
3. Never Store Tokens in localStorage
localStorage is accessible to any JavaScript running on the origin — XSS wins instantly. Keep access tokens in memory (closure variable) and refresh tokens in the hardened cookie described above.
4. Validate Every Claim
At minimum verify exp, nbf, iss, and aud. Reject tokens with missing or mismatched values. Use a strict audience whitelist — never accept a wildcard.
5. Maintain a Deny List
JWTs are stateless by design, but revocation requires state. Keep a short-lived deny list (Redis, Upstash KV) keyed by jti claim. Check it on every request. Expire entries when the token would have expired naturally.
6. Keep Payloads Minimal
The JWT body is base64-encoded, not encrypted. Never place secrets, PII, or internal role hierarchies in the payload. Store only a user identifier and essential scopes.
Meridian enforces RS256, 10-minute access tokens, and automatic refresh rotation out of the box. See the Auth Overview for integration details.