Free ToolBy GitIntel

JWT Best Practices 2026: What Most Implementations Get Wrong

Concrete security guidance for developers using JSON Web Tokens in production.

GitIntel tracks AI-generated code across your entire git history — giving every tool on this page the attribution layer that standard dev tooling misses.

Scan your codebase for JWT and auth library patterns with GitIntel

JSON Web Tokens appear in nearly every modern web application. They're also consistently misimplemented. The signature is correct, the claims are right, but the algorithm selection, storage strategy, or revocation story is broken. These are the patterns that matter in production.

Algorithm selection is the first mistake. The JWT spec allows alg: 'none' — a token with no signature. Many early JWT libraries accepted this, leading to trivial authentication bypasses. Libraries have fixed this, but the risk remains if you're not explicitly allowlisting algorithms. For symmetric signing (shared secret), use HS256 or HS512. For asymmetric (separate sign/verify keys), use RS256 or ES256. Prefer RS256 or ES256 in any system where the verification key is distributed — microservices, third-party consumers — so the signing key stays on one server.

Expiry is non-negotiable. Every JWT must have an exp claim. Access tokens should expire in 15-60 minutes. Refresh tokens can live longer (7-30 days) but need rotation on use. Without expiry, a stolen token is permanent. The tradeoff with short expiry is user experience: refresh token rotation balances security and session persistence.

Storage in browsers is the most debated topic. localStorage is convenient but vulnerable to XSS — any injected script can read it. HttpOnly cookies are immune to XSS but require CSRF protection. The current consensus for web apps: store access tokens in memory (JavaScript variable, not persisted), refresh tokens in HttpOnly cookies. This limits the blast radius of XSS to the current session.

Revocation is the hard problem. A valid JWT is self-contained and stateless — the server doesn't need to check a database. This means you can't "log out" a JWT by deleting a session row. Options: short expiry (accept the 15-minute window), a token blocklist (check a Redis set on each request — adds ~1ms latency), or refresh token rotation with revocation (invalidate the refresh token on logout, forcing re-authentication at next refresh). Each approach has cost; pick based on your threat model.

Never put sensitive data in the payload. JWT payloads are base64-encoded, not encrypted. Anyone with the token can decode and read the claims. userId and email are fine; password hashes, credit card numbers, or PII beyond what's necessary are not.

Frequently Asked Questions

Should I use JWT or session tokens?

Session tokens (a random opaque ID backed by a server-side store) are simpler, easier to revoke, and have a smaller attack surface. JWTs win when you need stateless verification across multiple services without a shared session store — microservices, CDN edge workers, or mobile apps hitting multiple backends. For a standard web app with a single backend, session tokens are often the safer default.

Can JWTs be hacked if the secret key is weak?

Yes. HS256 uses HMAC-SHA256, which is a symmetric MAC, not a password hash. A weak secret (less than 256 bits of entropy) can be brute-forced offline once an attacker has any valid JWT. Generate secrets with at least 32 random bytes: openssl rand -base64 32. Never use a human-readable passphrase as the signing secret.

What happens if a JWT is stolen?

If the token is valid and not expired, the attacker has full access until it expires. Short expiry limits the damage window. Token binding (tying the token to a client certificate or device fingerprint) prevents replay from a different machine, but adoption is limited. Refresh token rotation helps: a stolen refresh token that's used invalidates the entire token family, logging out the legitimate user and alerting you to the breach.

Is it safe to put JWTs in URL query parameters?

No. URLs appear in server logs, browser history, Referer headers, and CDN access logs. A JWT in a URL is effectively logged in plaintext across multiple systems. Always transmit JWTs in the Authorization header (Bearer scheme) or in a cookie. The only exception is one-time short-lived tokens for email verification links, where the tradeoff is explicit.

Start Using GitIntel Free

Open source. No account required. Works on any git repository.