Authentication comparison

JWT vs Session Tokens

Two fundamentally different approaches to keeping users logged in. The choice shapes how your backend scales, how quickly you can revoke access, and where you store secrets — and it comes up constantly in architecture reviews and security discussions.

TL;DR

  • Session tokens are random IDs stored server-side. Every request hits a session store to look up the user. Revocation is instant. Scales vertically or with a shared cache (Redis).
  • JWTs are self-contained signed tokens. The server validates the signature locally — no database call. Revocation before expiry is hard without extra infrastructure.
  • The real trade-off is stateless convenience vs. instant revocation control. Many production systems use both: a short-lived JWT as an access token and a session-like refresh token stored server-side.

Side-by-side comparison

AspectSession TokensJWT
StateStateful — session data lives on the serverStateless — all data encoded in the token
ScalabilityRequires sticky sessions or a shared session store (Redis)Any server validates independently — scales horizontally
RevocationInstant — delete the session recordHard — token is valid until expiry (need a blocklist to revoke early)
Storage (client)HttpOnly cookie (just the ID)HttpOnly cookie or localStorage (full token)
SizeSmall — 20–40 byte random IDLarger — typically 200–500 bytes of Base64 data
Server-side DB callEvery requestNone (signature check only)
Token rotationEasy — regenerate on login/privilege changeNeeds refresh-token rotation pattern
Best forWeb apps where instant logout mattersStateless APIs, microservices, mobile clients

When to use session-based auth

  • You need instant revocation. Compromised account? Delete the session record and the user is logged out immediately — no waiting for a token to expire.
  • Traditional web application. Server-rendered apps with a single backend and a cookie-based flow are a natural fit for sessions.
  • Sensitive operations (banking, healthcare). The ability to force-logout users across all devices by clearing their sessions is a compliance requirement in many regulated industries.
  • Small scale. If you have one server or a Redis instance, the session store is not a bottleneck.

When to use JWT

  • Stateless microservices. Each service validates the token locally without calling an auth service, reducing coupling and latency.
  • Mobile and SPA clients. A JWT in memory or secure storage travels with each API request without relying on cookie handling.
  • Cross-domain auth. JWTs work across domains naturally; cookies require careful SameSite and CORS configuration.
  • Short-lived access tokens with refresh tokens. A 5-minute JWT minimises the revocation window while keeping the system stateless for most requests.

English phrases engineers use

JWT conversations

  • "We use JWT for stateless auth across our microservices."
  • "The token is signed with HS256 using a shared secret."
  • "You need to validate the signature before trusting any claim."
  • "The access token expires in 15 minutes; the refresh token lasts 7 days."
  • "We store a JTI in Redis to maintain a blocklist for revoked tokens."

Session conversations

  • "The session store is a bottleneck under high load — we're moving to Redis."
  • "We rotate the session ID on login to prevent session fixation."
  • "When the user logs out, we invalidate the session immediately."
  • "We're using sticky sessions on the load balancer for now."
  • "The session expires after 30 minutes of inactivity."

Key vocabulary

  • Claim — a key-value pair in the JWT payload (e.g., "sub": "user_42", "exp": 1700000000).
  • Signature — a cryptographic hash of the header and payload, verifying the token was not modified.
  • HS256 / RS256 — HMAC-SHA256 (symmetric, shared secret) vs. RSA-SHA256 (asymmetric, public/private key pair).
  • Refresh token — a long-lived token used only to obtain a new short-lived access token.
  • Session fixation — an attack where an adversary sets a known session ID before login; mitigated by rotating the ID on authentication.
  • JTI (JWT ID) — a unique identifier claim used to track or blocklist individual tokens.
  • HttpOnly cookie — a cookie inaccessible to JavaScript, reducing XSS exposure.

Quick decision tree

  • Need instant logout / revocation across all devices → Sessions
  • Stateless microservices that must validate tokens independently → JWT
  • Traditional server-rendered web app → Sessions
  • Mobile app or cross-domain SPA → JWT
  • Regulated industry with forced-logout requirements → Sessions
  • High horizontal scale, want to avoid shared session store → JWT
  • Both scale and revocation matter → JWT access token + server-side refresh token

Frequently asked questions

Can you revoke a JWT before it expires?

Not easily — that is the main trade-off of stateless tokens. Because the server keeps no state, a valid JWT is accepted until it expires. Common workarounds include short expiry times (5–15 minutes) combined with refresh tokens, or maintaining a server-side blocklist (which reintroduces state). Some teams use Redis to store revoked JTI (JWT ID) values.

Is JWT more secure than session tokens?

Neither is inherently more secure — they have different threat surfaces. JWTs stored in localStorage are vulnerable to XSS; JWTs in HttpOnly cookies have similar protections to session cookies. Session tokens can be revoked instantly but are vulnerable to session fixation if not rotated on login. Security depends far more on implementation than on the choice of mechanism.

What is a refresh token?

A refresh token is a long-lived credential (days to weeks) stored securely, used only to obtain a new short-lived access token (JWT). The pattern lets you keep access tokens short-lived (reducing the revocation window) while not forcing users to log in frequently. Refresh tokens should be rotated on each use and stored in HttpOnly cookies.