Back to the blog
Databaseยท Jul 9, 2026ยท 8 min read

JWT vs sessions in 2026: the auth decision most teams get wrong

JWTs are not safer than sessions. Sessions are not simpler than JWTs. The right choice is determined by your deployment target and revocation requirements, not preference.

#security#auth#jwt#typescript

The JWT vs session debate has been running for a decade and still produces bad architecture decisions because developers pick one based on preference rather than constraints. The choice is structural, not aesthetic โ€” your deployment target, scale requirements, and revocation needs determine the right answer more than any opinion about which approach is better.

What each approach actually does

Server sessions store state on the server: a session ID is issued to the client in an HTTP-only cookie, and every request looks up that ID in a session store (Redis, database). The server is the source of truth โ€” revocation is instant. JWTs store state in the token itself: a signed payload sent to the client, verified on each request by checking the signature with no server lookup. The server has no memory of the token โ€” it either trusts the signature or it doesn't.

// Session pattern: server is the source of truth
// Revocation: delete the session row, immediately invalid
const session = await getSession(req.cookies.sessionId);
if (!session || session.expiresAt < Date.now()) throw unauthorized();

// JWT pattern: token is the source of truth
// Revocation: can't revoke until expiry without a blocklist
const payload = jwt.verify(token, SECRET_KEY);
// If this token was issued before a password reset, it still works

The revocation problem with JWTs

The most understated problem with JWTs is revocation. A signed JWT is valid until its expiry โ€” if you need to log a user out immediately (password change, account compromise, admin ban), a stateless JWT gives you no mechanism to do this without reintroducing server-side state (a blocklist), which undermines the stateless advantage. The practical solution: short-expiry JWTs (15 minutes) plus an HTTP-only refresh token that the server can revoke. This hybrid is the production standard in 2026.

Decision guide

  • Server sessions in Redis: first-party web apps where instant revocation matters, server-rendered apps, single-origin deployments. Simple, mature, correct.
  • Short-lived JWTs + HTTP-only refresh token: APIs for mobile clients, microservice auth, multi-origin apps. More complex but correct if you implement refresh token revocation.
  • Never: JWTs in localStorage (XSS-accessible), long-lived JWTs without revocation, sessions in process memory (doesn't survive restart or horizontal scale).
  • Non-negotiable regardless of approach: HTTPS everywhere, Secure + HttpOnly + SameSite on all auth cookies, rotate tokens on any privilege change.

Written by Appesto Engineering.