JWT vs session cookies: which auth should you use?

"Sessions vs JWTs" is really a question about where auth state lives: on the server (a session ID pointing at a server-side record) or inside the credential itself (a signed token the server verifies statelessly). Neither is universally better; they trade the same properties in opposite directions.

Server-side sessionJWT
StateOn the server (memory/Redis/DB)In the token; server stateless
RevocationInstant — delete the recordHard — valid until exp unless you add a denylist
Horizontal scalingNeeds a shared session storeAny node with the public key can verify
Cross-service authAwkward — every service hits the storeNatural — services verify locally
Size per request~32-byte cookieHundreds of bytes to several KB

How each one works

A session cookie is a random ID; everything about the user stays server-side, so nothing sensitive ever leaves and the record can be destroyed at any moment. A JWT carries its claims with it — sub, exp, roles — over a signature, so any service holding the issuer's public key verifies it without a lookup. (Anyone can also read those claims: a JWT is signed, not encrypted.)

The revocation problem

The signature that makes JWTs stateless also makes them irrevocable: logging out, deleting an account, or detecting a stolen token doesn't invalidate copies already issued. The standard mitigation is short-lived access tokens (minutes, enforced by exp) plus a revocable refresh token — see ID vs access vs refresh tokens — and, where you need per-token kill switches, a denylist keyed by jti. Note what happened: you reintroduced server state to fix statelessness. If you end up checking a store on every request anyway, a session would have been simpler.

When each is the right call

  • Sessions: a server-rendered or single-backend web app, same-site clients, instant logout as a hard requirement. Boring and correct.
  • JWTs: APIs consumed by multiple services, microservices verifying tokens from a shared identity provider, mobile/SPA clients on OAuth 2.0 / OIDC flows, or cross-domain federation.
  • Hybrid (very common): a session cookie for the first-party web app, JWTs minted by the same identity provider for API and service-to-service calls.

If you're inheriting a JWT setup and want to see what's actually inside those tokens, decode one in the TokenPrism debugger — it flags weak spots like missing exp or an unexpected algorithm as you paste.