Architecture & Methodology
Official siteJWT
JWT — stateless signed tokens for authentication and authorization, deployed with the validation and lifecycle discipline they demand.
Overview
JWTs are a compact, signed way to carry identity and claims between services without a shared session store. I use them where statelessness genuinely pays — distributed services that can verify a token locally instead of round-tripping an auth server.
Their reputation problem is almost always misuse, not the format: tokens need strict algorithm pinning, short expiries, audience and issuer validation, and a revocation path for leaked tokens. I treat signatures as cryptography, never as config.
Because a signed token is a long-lived grant, I limit what it carries — no PII beyond need, scopes over all-or-nothing, and refresh flows that keep standing sessions while access tokens stay short.
A JWT has three parts — header, claims, and signature — and I pay attention to all of them. The header pins the algorithm (`RS256`, never `none`), the claims state who issued it and for whom, and the signature is verified with the right key from the right source.
Verification order matters and I enforce it strictly: check the signature, then the audience, issuer, and expiry. A token that is validly signed but aimed at another service is a token to reject, not one to trust.
Key management is the real security surface. I keep signing keys out of the token path, rotate them on a schedule, and use JWKS so consumers can re-fetch public keys without a redeploy. A leak of the signing key is the endgame, so it must never happen.
Statelessness has a cost: you cannot simply revoke a token you no longer trust. My answer is a short access-token lifetime plus a refresh flow, and a lightweight revocation list only for the tokens that actually need to die early.
I keep the claim set minimal. The token carries only what consumers need — identity, scopes, expiry — and nothing sensitive. Over-stuffing a JWT with data defeats its purpose and leaks information into a value you must not be precious with.
JWTs are a tool, not a default. Where a shared session store and a cookie serve a single-domain app better, I use that. JWTs earn their place across distributed services that must verify each other without centralised state.
How I Work With JWT
I pin the algorithm and never allow downgrade. `RS256` and a verified key, with `none` and weak algorithms rejected outright — signatures are cryptography, not config.
Verification order is strict and always the same: signature first, then issuer, audience, and expiry. A validly signed token aimed at the wrong service is rejected.
Keys are managed as the crown jewels. Signing keys live out of the token path, rotate on a schedule, and are served to consumers via JWKS so verification never requires a redeploy.
The claim set is minimal. I carry only what consumers need — identity, scopes, expiry — and nothing sensitive, because a token is not a vault.
Lifetimes are short for access tokens, and standing sessions ride refresh-token rotation so a leaked access token is a small, expiring problem.
Statelessness is bought with discipline. Where revocation matters, I add a lightweight revocation path for the specific tokens that need to die early, rather than pretending a JWT is revocable by nature.
I keep crypto libraries current and pinned. A vulnerable parser is a vulnerability, so dependency hygiene is part of the security posture.
Consumers validate consistently. Every service verifies issuer, audience, and signature the same way rather than trusting the header alone.
Where a shared session store and cookie serve a single-domain app better, I use that. JWTs earn their place across distributed services that must verify each other without central state.