JWT Security Mistakes Developers Make
JWT is widely used but widely misimplemented. These are the most critical security mistakes developers make with JWT — and how to fix them.
Mistake 1 — Using the "none" algorithm
Some JWT libraries accept tokens with alg: "none" in the header. This means no signature — anyone can create a valid token by simply setting the algorithm to none and removing the signature.
Attack example:
// Attacker creates this header
{ "alg": "none", "typ": "JWT" }
// With this payload
{ "sub": "admin", "role": "admin" }
// No signature needed!
// Vulnerable servers accept this as validFix:
// Always specify allowed algorithms
jwt.verify(token, secret, {
algorithms: ['HS256'] // never include 'none'
})Mistake 2 — Storing sensitive data in JWT payload
The JWT payload is Base64 encoded — not encrypted. Anyone who intercepts your token can decode and read the payload without knowing your secret key.
Never store in JWT:
// ❌ NEVER put these in JWT payload
{
"password": "user_password",
"creditCard": "4111111111111111",
"ssn": "123-45-6789",
"secretApiKey": "sk_live_xxx"
}Store only what's needed:
// ✅ Safe to store in JWT
{
"sub": "user_id_123",
"role": "admin",
"email": "user@example.com",
"iat": 1716000000,
"exp": 1716003600
}Mistake 3 — Weak secret keys
Short or predictable HS256 secrets can be brute forced. Attackers can use tools like hashcat to crack weak JWT secrets offline once they have a token.
// ❌ Weak secrets
"secret"
"password"
"jwt_secret"
"1234567890"
// ✅ Generate strong secrets
// Node.js
require('crypto').randomBytes(64).toString('hex')
// Result:
// a8f5f167f44f4964e6c998dee827110c
// d14a028c2a3a2bc9476102bb288234c4
// (64 bytes = 128 hex characters)Mistake 4 — Not validating claims
Verifying the signature is not enough. You must also validate the claims — especially iss (issuer),aud (audience) and exp (expiry).
// Always validate these claims
jwt.verify(token, secret, {
algorithms: ['HS256'],
issuer: 'https://auth.yourapp.com',
audience: 'https://api.yourapp.com',
// exp is checked automatically
})Mistake 5 — Storing JWT in localStorage
localStorage is accessible to any JavaScript running on your page. If your site has an XSS vulnerability an attacker can steal all JWT tokens stored in localStorage.
| Storage | XSS Risk | CSRF Risk | Recommendation |
|---|---|---|---|
| localStorage | ❌ High | ✅ None | Avoid for auth tokens |
| sessionStorage | ❌ High | ✅ None | Avoid for auth tokens |
| httpOnly Cookie | ✅ Safe | ⚠️ Medium | ✅ Recommended |
| Memory (React state) | ✅ Safe | ✅ None | ✅ Best for SPAs |
JWT Security checklist
Inspect your JWT tokens safely
Our JWT Decoder runs entirely in your browser. Your tokens never leave your device.
Open JWT Decoder →