Common JWT security mistakes - cover art

JWT and security 17 min read

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

Hardening checklist

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

Browse all tools