JWT Security: Best Practices Every Developer Should Know
The 7 Most Common JWT Security Mistakes
JWT is a powerful authentication mechanism — but it's frequently misimplemented. Here are the most common security mistakes:
- No expiration time (exp): Tokens without
expare valid forever. A stolen token grants permanent access. Always set short lifetimes (15–60 minutes for access tokens). - Using the `none` algorithm: Some early JWT libraries accepted
alg: none, meaning no signature. Never accept unsigned tokens in production. - Storing JWTs in localStorage: Accessible to any JavaScript on the page, including XSS payloads. Prefer
httpOnlycookies. - Not validating the `iss` (issuer) claim: Allows tokens from any issuer to be accepted.
- Symmetric keys that are too short: For HS256, use a secret of at least 256 bits (32 bytes).
- Not rotating secrets: If your signing secret leaks, all tokens signed with it are compromised.
- Trusting the `kid` (key ID) without validation: Advanced but critical — always whitelist valid key IDs.
Access Tokens vs Refresh Tokens: The Right Architecture
A common pattern for JWT-based authentication uses two token types:
Access Token (short-lived, 15 min):
- Sent with every API request in Authorization: Bearer <token>
- Stateless — no database lookup needed to verify
- If stolen, attacker has limited window before it expires
Refresh Token (long-lived, 7–30 days):
- Stored securely (httpOnly cookie or server-side session)
- Used only to obtain a new access token
- Can be revoked by deleting it server-side
This separation is the industry best practice. It gives you the performance of stateless auth (no DB lookup per request) with the security of revocable sessions.
Never store sensitive user data in the JWT payload — it's only Base64-encoded, not encrypted. Anyone who intercepts it can read it.
Algorithm Selection: HS256 vs RS256 vs ES256
Choosing the right signing algorithm matters:
- HS256 (HMAC-SHA256): Fast, simple. Single shared secret. Good for monolithic apps where the same service issues and verifies tokens. Risk: if any service that can verify tokens is compromised, attacker can forge tokens.
- RS256 (RSA-SHA256): Asymmetric. Private key signs, public key verifies. Ideal for microservices — each service can verify without access to the signing key. Slower than HS256.
- ES256 (ECDSA with P-256): Like RS256 but with smaller, faster keys. Modern choice for APIs with high throughput requirements.
Recommendation: For new projects, use RS256 or ES256. The performance overhead is minimal compared to the security benefit.