JSON Web Tokens are everywhere in modern authentication, and they are misunderstood almost as often as they are used. The token format itself is fine. The breaches come from a recurring set of implementation mistakes. Here are eight that have caused real-world compromises, and how to avoid each. They sit underneath the authentication layer in our API security checklist.
1. Trusting the algorithm in the token
A classic attack abuses servers that read the signing algorithm from the token header. An attacker switches it to "none" or downgrades it, and a naive verifier accepts a forged token. Always enforce the expected algorithm on the server and reject anything else, rather than trusting the token to declare how it should be verified.
2. Putting secrets in the payload
A JWT payload is encoded, not encrypted. Anyone holding the token can read it. Putting sensitive data in there exposes it to anyone who intercepts or inspects the token. Keep the payload to non-sensitive identifiers and claims.
3. Weak or shared signing keys
A short, guessable signing secret can be brute-forced offline, after which an attacker can mint valid tokens at will. Use a long, random key, store it securely, and never commit it to source control, which ties directly into securing your build pipeline.
4. No expiry, or expiry too long
A token that never expires is a permanent credential, so a single leak is forever. Keep access tokens short-lived and use a separate refresh mechanism. The shorter the window, the smaller the blast radius of a stolen token.
5. No way to revoke
Stateless tokens are valid until they expire, which is awkward when you need to log someone out or respond to a compromise immediately. Maintain a revocation list or keep access-token lifetimes short enough that revocation is rarely needed, ideally both.
6. Storing tokens unsafely in the browser
Tokens in places accessible to JavaScript are exposed to cross-site scripting. Prefer secure, http-only cookies with appropriate flags so a script flaw cannot read the token. How you store the token is as important as how you sign it.
7. Skipping full validation
Verifying the signature is not enough. Check the issuer, the audience, and the expiry on every request. A token that is validly signed but intended for a different service or already expired must still be rejected.
The pattern behind the mistakes
Look across these eight errors and a single theme emerges: trouble comes from treating a token as inherently trustworthy rather than as a claim to be verified rigorously every time. The algorithm, the issuer, the audience, the expiry, the storage location, and the signing key are each a place where misplaced trust opens a door. A useful mental exercise is to assume an attacker has seen your token and can craft their own, then ask what stops a forged or stolen one from working. If the honest answer is a long random key kept secret, strict server-side verification of every claim, short lifetimes, and safe storage, you are in good shape. If any of those is weak, that is your vulnerability. The token format is sound; the security lives entirely in the discipline of how you issue, store, and verify.
8. Using JWTs where a session would be simpler
JWTs shine for stateless, cross-service authentication. For a single traditional web application, a server session is often simpler and easier to revoke. Choosing the token because it is fashionable, rather than because it fits, is its own mistake. If you want your authentication reviewed against these pitfalls, our security team audits exactly this.