JSON Web Tokens (JWTs) have become the default authentication mechanism for modern web applications. Their flexibility is a strength — and a liability. Misconfigured JWTs are responsible for a significant portion of authentication bypasses in production systems.
Mistake #1: Using a Weak Secret Key
HS256-signed JWTs rely entirely on the strength of the secret key. A short or predictable key can be brute-forced. Use a cryptographically random secret of at least 256 bits. Generate it with openssl rand -base64 32 and store it in your secrets manager.
Mistake #2: The Algorithm Confusion Attack
The JWT header specifies the signing algorithm. Some vulnerable libraries accept the algorithm specified in the token header rather than enforcing one server-side. An attacker can change the algorithm to none — bypassing signature verification entirely. Always specify and enforce the expected algorithm explicitly on your server.
Mistake #3: Storing JWTs in localStorage
localStorage is accessible to JavaScript, making any stored token vulnerable to XSS attacks. Store access tokens in memory and refresh tokens in httpOnly, Secure, SameSite=Strict cookies instead.
Mistake #4: Not Validating Claims
Verifying the signature is not enough. Always validate the exp (expiration), iss (issuer), and aud (audience) claims. An attacker who obtains a valid token from one service should not be able to use it against another.
Mistake #5: Excessively Long Expiration Times
Long-lived access tokens extend the window of damage if a token is compromised. Keep access token lifetimes short (15 minutes is common) and implement refresh token rotation for longer sessions.
Mistake #6: Including Sensitive Data in the Payload
JWT payloads are base64-encoded — not encrypted. Anyone who obtains the token can decode the payload. Never store passwords, PII, or secrets in JWT claims. Use opaque references instead.
Mistake #7: No Token Revocation Strategy
JWTs are stateless by design. Once issued, they are valid until expiry — even if the user logs out or their account is compromised. Implement a token denylist (stored in Redis) or use short expiry with refresh token rotation to enable effective revocation.
Conclusion
JWTs are not inherently insecure — but they require careful implementation. Audit your JWT handling against these seven mistakes and use a well-maintained library like jose or jsonwebtoken with explicit algorithm enforcement. When in doubt, consider session-based authentication for simpler security guarantees.