Featured image of post Comparing JWT Tokens vs Stateful Sessions in Web Security Featured image of post Comparing JWT Tokens vs Stateful Sessions in Web Security

Comparing JWT Tokens vs Stateful Sessions in Web Security

Critique stateless JWT tokens vs stateful server database sessions regarding revoke properties and local safety.

Introduction

Authentication is the backbone of every web application. Two dominant patterns have emerged: stateless JWT (JSON Web Token) auth and stateful session-based auth. Both solve the same problem — verifying who a user is on subsequent requests — but they differ fundamentally in storage, revocation, and security properties. This article provides a detailed comparison to help you choose the right approach for your application.


JWT Structure

A JWT is a self-contained token consisting of three base64url-encoded segments separated by dots:

header.payload.signature
// Header
{
  "alg": "HS256",
  "typ": "JWT"
}
// Payload
{
  "sub": "user123",
  "iat": 1712345678,
  "exp": 1712349278,
  "role": "admin"
}
// Signature (HMAC-SHA256 of header + payload)
SegmentContents
HeaderAlgorithm (HS256, RS256) and token type
PayloadClaims — sub (subject), iat (issued at), exp (expiration), custom data
SignatureVerifies the token hasn’t been tampered with

Since the payload is only base64-encoded (not encrypted), sensitive data must never be placed in the payload unless using JWE (JSON Web Encryption).


Session-Based Auth

In session-based auth, the server stores session data (typically in memory, Redis, or a database). The client only holds a session ID (a random opaque string) in a cookie:


Head-to-Head Comparison

AspectJWTSession
Storage locationClient holds all dataServer holds session data
Server stateStateless — no DB lookup neededStateful — requires session store query
ScalabilityExcellent — no shared session storeRequires centralized Redis/DB for multi-instance
RevocationDifficult — valid until expImmediate — delete session from store
Token sizeLarger (hundreds of bytes)Small (session ID ~32 bytes)
XSS vulnerabilityToken accessible to JS (localStorage)httpOnly cookie not accessible to JS
CSRF protectionRequires manual handlingSameSite cookie + CSRF token

Revocation Challenge with JWT

The most significant weakness of JWT is revocation. Once issued, a JWT remains valid until its exp claim. If a user logs out, changes password, or is banned, the token cannot be invalidated without server-side state — which defeats the stateless premise.

Mitigation Strategies

1. Short-lived access tokens + refresh tokens:

// Access token: 15 minutes
// Refresh token: 7 days (stored in database)

The access token has a short TTL so damage is limited if leaked. The refresh token is stored server-side, so it can be revoked.

2. Token blacklist (deny-list):

// On logout, add jti (JWT ID) to Redis with TTL matching token expiry
await redis.set(`blacklist:${jti}`, 'true', 'EX', remainingTTL);

This reintroduces server state but only for revoked tokens, not all active sessions.

3. Rotate token signature key:

Changing the signing key invalidates all tokens — a blunt but effective tool for emergencies.


XSS and XSRF Considerations

ThreatJWT (localStorage)Session (httpOnly cookie)
XSSToken stolen via document.cookie or localStorageToken not accessible to JS (httpOnly)
CSRFNot vulnerable (manual Authorization header)Vulnerable without SameSite or CSRF token

JWTs stored in localStorage are vulnerable to XSS — any injected script can read them. HttpOnly cookies prevent this but require CSRF protection since cookies are automatically sent.

Best practice for JWTs: Store the access token in an httpOnly, Secure, SameSite=Strict cookie (not localStorage). The server reads it from the Authorization header, not a cookie, to avoid CSRF.

// Set JWT in httpOnly cookie
res.cookie('token', jwt, {
  httpOnly: true,
  secure: true,
  sameSite: 'strict',
  maxAge: 15 * 60 * 1000
});

Hybrid Approaches

Many production systems combine both patterns:

ApproachAccess TokenRefresh Token
JWT-onlyJWT in memoryJWT with long exp
Session-styleOpaque session ID
HybridShort-lived JWT (15 min)Opaque refresh token in DB

The hybrid model gives you the stateless efficiency of JWT for most requests while retaining revocation capability through the refresh token.


Decision Matrix

Your PriorityRecommended Approach
Minimal server DB loadJWT (stateless)
Instant user logout / banSession-based
Microservices / API gatewaysJWT (pass-through)
Mobile appsJWT (no cookie storage)
Server-rendered web appsSession (httpOnly cookie)
Third-party API accessJWT (bearer token)

Conclusion

There is no universal winner. JWT excels in distributed systems, mobile apps, and API-first architectures where statelessness is valuable. Session auth provides superior control for revocation, logout, and server-side security enforcement. The hybrid pattern — short-lived JWTs backed by revocable refresh tokens — offers a pragmatic compromise that captures the strengths of both approaches while mitigating their weaknesses.