advanced 2 min answer

A team is designing token-based authentication for a distributed system. What are the significant design decisions, and which common JWT choices cause problems later?

jwttokensrevocationsessionsauthentication
Show the full answer Hide the answer

The central trade: stateless versus revocable

A self-contained token that services validate by signature requires no lookup — that is its entire advantage. It is also, for the same reason, valid until it expires, and cannot be revoked.

Every difficulty with JWTs descends from this. A user logs out, an account is disabled, permissions are reduced, a device is lost, a session is compromised — and the outstanding tokens continue to work.

Resolving it

  • Short expiry with refresh tokens. Access tokens live minutes; refresh tokens are checked against a store at refresh time. This bounds the revocation window to the access token's lifetime, which is the standard and correct answer for most systems.
  • A revocation list for the rare cases, checked at the gateway rather than in every service — small, because entries expire with the tokens.
  • Session identifiers instead of self-contained tokens where revocation must be immediate. If every request already hits a shared store, an opaque session identifier is simpler, immediately revocable and does not leak claims. Many systems using JWTs would be better served by sessions and adopted tokens by default.
  • A hybrid: opaque tokens externally, exchanged for short-lived signed tokens at the gateway for internal propagation. This is the pattern most large systems converge on, and it gets both properties.

The choices that cause problems later

  • Long expiry to avoid implementing refresh. Every security incident then has an unbounded tail.
  • Putting authorisation decisions in the token. Roles and permissions embedded at issue time are stale as soon as they change, so a permission revocation does not take effect until expiry. Prefer identity in the token and authorisation evaluated at request time.
  • Putting personal data in the token. It is base64, not encrypted, and it is stored in browsers, logged by proxies and sent to third parties.
  • Accepting the alg header from the token. The classic vulnerability class — none, or algorithm confusion between symmetric and asymmetric. The verifier must specify the expected algorithm, not read it from the untrusted input.
  • No kid header or key rotation plan, making key rotation a coordinated outage.
  • Tokens in local storage, accessible to any script on the page. HttpOnly cookies with appropriate SameSite settings are safer for browser clients, with CSRF handled separately.
  • No audience or issuer validation, so a token issued for one service is accepted by another.
  • Trusting tokens from other internal services without validation, which reintroduces implicit network trust inside a system that adopted tokens to remove it.

What to validate, every time

Signature, expiry, not-before, issuer, audience, and the algorithm against an expected value. Use a maintained library; hand-rolled validation is where the vulnerabilities are, and the failure is silent because a wrongly-validated token still parses.