2 min lesson
JWT failure modes to name unprompted
For each case in "JWT failure modes to name unprompted", name the signal and the response you would use.
Step 1 of 2
JWT failure modes to name unpromptedthe security-credibility checklist
A token claims it's unsigned and a naive verifier accepts it.
Pin the expected algorithm server-side; never trust the token's own alg header.
RS256 token re-signed as HS256 using the public key as the HMAC secret.
Same fix: hard-code the accepted alg, separate signing from verification keys.
A token minted for service A is replayed against service B.
Validate issuer and audience on every verify, not just the signature.
Stuffing every permission into the JWT bloats every request header.
Keep claims minimal; resolve fine-grained authz server-side.
Two more that bite at scale: tokens that never set exp and signing keys that are short, hand-rolled or shared across environments. A leaked HS256 secret lets anyone forge tokens for everyone, which is why asymmetric RS256/ES256 with a private signing key is the default at a 1M-user tool.
"I'd use short-lived access JWTs for the hot path so most requests verify locally and stay cheap, with refresh tokens and a token-version check for revocation. The cost is a bounded staleness window of about one access-token TTL, and I'd keep that under fifteen minutes so a compromised account can't stay live for long."
At 1M+ DAU, pure server-side sessions put a store lookup on every request, so that store becomes a single point of failure for the whole product. If Redis hiccups, nobody can do anything. Stateless JWT verification degrades gracefully because it needs no external call to authenticate. That makes it a reliability argument as well as a performance one, and it's the framing Cursor wants from a Core Services EM.