Facebook Pixel

Common JWT Mistakes (and How to Avoid Them)

JWT is easy to misuse. Here are the common mistakes and how to avoid them.

Common JWT Mistakes

JWT is easy to misuse. Here are the common mistakes and how to avoid them.

Mistake 1: Storing JWT in LocalStorage

LocalStorage is open to XSS. Any script (including injected ones) can read it. Fix: store JWT in an httpOnly, secure, sameSite cookie. Scripts cannot read it.

Mistake 2: No Expiry

You sign a token with no expiry. It lives forever. If stolen, the attacker has access forever. Fix: always set expiresIn. Use short expiry (15 min) with a refresh token (7 days).

Mistake 3: Putting Sensitive Data in the Payload

The payload is base64-encoded, not encrypted. Anyone with the token can read it. Fix: only put non-sensitive claims (userId, role). Never put passwords, secrets, or PII in the payload.

Mistake 4: Using jwt.decode Instead of jwt.verify

jwt.decode just reads the payload without checking the signature. An attacker can forge a token. Fix: always use jwt.verify. It checks the signature and expiry.

Mistake 5: Weak JWT Secret

You use 'secret' or 'password' as the JWT secret. An attacker can forge tokens. Fix: use a long random string (at least 32 chars). Store it in an env var. Rotate periodically.

Mistake 6: Not Handling Expired Tokens

The client gets a 401 on every request after the token expires. Fix: use a refresh token to get a new access token silently. Or handle 401 in the client and redirect to login.

Mistake 7: Not Revoking on Logout

You clear the cookie but the token is still valid until it expires. Fix: use short expiry so the window is small. For real revocation, use a refresh token (stored in DB) and delete it on logout.

Mistake 8: Same Secret Across Environments

You use the same JWT secret in dev and prod. A leak in dev exposes prod. Fix: use different secrets for dev and prod. Load from env vars.

Mistake 9: No Algorithm Verification

You accept any algorithm in the header. Some libraries have had vulnerabilities where 'none' alg was accepted. Fix: specify the algorithm in jwt.verify: { algorithms: ['HS256'] }.

Mistake 10: Big Payloads

You put everything (user profile, permissions, history) in the payload. Tokens get huge. Every request sends it. Fix: only put the userId. Load the rest from the DB on each request.

The Takeaway

Common JWT mistakes: storing in LocalStorage (use httpOnly cookies), no expiry (use short expiry with refresh), sensitive data in payload (only put userId and role), jwt.decode instead of verify, weak secret, no expired token handling, no revocation on logout, same secret across envs, no algorithm verification, and big payloads.

Storing in LocalStorage, no expiry, sensitive data in payload, jwt.decode instead of verify, weak secret, no expired token handling, no revocation on logout, same secret across envs, no algorithm verification, and big payloads.

LocalStorage is open to XSS. Any script (including injected ones) can read it and send the token to an attacker. Use an httpOnly, secure, sameSite cookie. Scripts cannot read it.

jwt.decode just reads the payload without checking the signature. An attacker can forge a token with any payload. jwt.verify checks the signature and expiry, so forged tokens are rejected.

Only non-sensitive claims: userId and role. The payload is base64-encoded, not encrypted. Anyone with the token can read it. Never put passwords, secrets, or PII in the payload.

Use short expiry so the window is small. For real revocation, use a refresh token (stored in DB) and delete it on logout. The access token expires in 15 min anyway. Without refresh tokens, you cannot truly revoke a JWT before expiry without a blacklist.

Ready to master Node.js completely?

Want to upskill yourself, crack your next interview, and get your dream job? Join our comprehensive course to dive deeper with high-quality video tutorials, solve interview questions, and a premium community.

Please Login.
Please Login.
Please Login.
Please Login.