Common JWT security mistakes
July 21, 2026 · 17 min read
JWT libraries are mature, yet breaches still trace to misconfiguration: accepting alg: none, using HS256 with a six-character secret, or trusting decoded JSON without signature verification. This checklist targets mistakes seen in real incidents and code reviews.
Algorithm confusion and alg none
Attackers may craft a token with "alg":"none" or switch RS256 to HS256 by signing with the public key as if it were an HMAC secret. Mitigation: allowlist algorithms in code (['RS256'] only), use frameworks that ignore the header’s alg when verifying, and disable none entirely.
// Good: pin algorithm at verify time
await jwtVerify(token, publicKey, {
algorithms: ["RS256"],
issuer: "https://auth.example.com",
});
Weak, shared, or leaked secrets
HS256 with a guessable secret falls to offline brute force. Secrets in Git, Slack, or client-side mobile bundles invalidate every token. Use 256+ bits of entropy from a CSPRNG, rotate on leak, and prefer RS256/ES256 when many teams touch verification keys.
Skipping exp, iss, and aud validation
Decoding without verification accepts forged tokens. Even after verify, failing to check exp and nbf allows replay windows. aud stops tokens minted for one API from working on another. iss blocks cross-tenant confusion when multiple IdPs exist.
Unsafe client storage and logging
- localStorage + XSS = full account takeover until token expires.
- Logging Authorization headers in INFO level ships bearer tokens to Splunk.
- Putting PII or roles in payload that should live server-side increases exposure when decoded.
Hardening checklist
- 1. Verify signature, algorithm, exp, iss, aud on every request.
- 2. Keep access token TTL short (5–15 minutes); rotate refresh tokens.
- 3. Use asymmetric keys for multi-service verification; publish JWKS.
- 4. Never implement crypto yourself - use jose, PyJWT, or java-jwt.
- 5. Add security tests that submit tampered tokens and expect 401.
FAQ
- Is storing JWTs in HttpOnly cookies safe?
- Safer than localStorage for XSS, but you must implement CSRF protection for state-changing requests.
- Should I put roles in the JWT?
- Only if you accept stale roles until expiry or revalidate on sensitive actions. Many systems load roles from DB using sub.
- What is the minimum HS256 secret size?
- Treat the secret like a 256-bit key (32 random bytes). Shorter secrets are vulnerable to brute force.
- Can I trust the alg field in the header?
- Only after verification with an allowlisted algorithm. Never branch verification logic solely on unverified header JSON.
Related: HS256 vs RS256 · JWT expiration