JWT vs Session Cookies: Evaluating the 'Stop Using JWTs' Debate

The debate over using JSON Web Tokens (JWTs) for user authentication often centers on a fundamental trade-off: the convenience of statelessness versus the security of immediate revocation. While some argue that JWTs should be avoided entirely for browser-based sessions in favor of stateful session cookies, the consensus among practitioners is that JWTs remain highly effective for specific use cases, particularly service-to-service communication and distributed architectures.

The Core Conflict: Statelessness vs. Revocation

The primary technical criticism of JWTs in session management is the inability to invalidate an individual token before its expiration date without introducing state into the system.

In a traditional stateful session, the server stores a session ID in a database or cache. To log a user out or terminate a compromised session, the server simply deletes the session record, rendering the session ID useless immediately. Because JWTs are self-contained and verified cryptographically, they remain valid until their exp (expiration) timestamp is reached, regardless of whether the user has logged out or their permissions have changed.

Implementing Revocation in JWTs

To solve the revocation problem, developers often implement one of the following patterns:

  • Revocation Lists (Blocklists): Storing the unique identifier (jti) of revoked tokens. This approach is often more efficient than full session storage because the list only contains tokens that are revoked and not yet expired, rather than every active session.
  • Minimum Issued-At (iat) Timestamps: Setting a minimum_issued_at field on the user object. Any token issued before this timestamp is considered invalid. This is a common pattern for "Logout from all devices" functionality.
  • Short-Lived Tokens with Refresh Cycles: Using access tokens with very short lifetimes (e.g., 5–15 minutes) and a separate refresh token to obtain new ones. This limits the window of opportunity for an attacker using a stolen token.

Architectural Use Cases: When to Use Which

Technical consensus suggests that the "correct" tool depends on the architectural boundaries of the application.

Browser-Based User Sessions

For simple monolithic applications where the frontend and backend reside on the same domain, stateful session cookies are often preferred. They are simpler to implement and provide immediate control over session termination. Critics of JWTs in the browser point out that storing tokens in localStorage exposes them to Cross-Site Scripting (XSS) attacks, whereas httpOnly cookies are inaccessible to JavaScript.

Service-to-Service (S2S) Communication

JWTs are widely considered the superior choice for S2S interactions. In a microservices architecture, a service can verify a JWT's signature using a public key without needing to make a synchronous network call to a central authentication service for every request. This reduces latency and prevents the authentication service from becoming a single point of failure or a performance bottleneck.

Edge Authentication and WAFs

JWTs allow for "defense in depth" at the network edge. A Web Application Firewall (WAF) or API Gateway can perform initial validation (checking expiration, issuer, and signature) before the request ever reaches the backend. This filters out malformed or expired requests without consuming application database resources.

Security Considerations and Alternatives

The Role of Storage

Security risks are often attributed to where the token is stored rather than the token format itself. A JWT stored in an httpOnly cookie provides similar security properties to a session ID stored in an httpOnly cookie, as both are subject to session hijacking but protected from XSS exfiltration.

PASETO (Platform-Agnostic Security Tokens)

Some security experts recommend PASETO as a more secure alternative to JWT. Unlike JWT, which allows the developer to choose the encryption and signing algorithms (leading to potential "alg: none" vulnerabilities or weak key choices), PASETO uses "versioned" protocols that mandate specific, secure cryptographic primitives, removing the opportunity for implementation errors.

DPoP (Demonstrating Proof-of-Possession)

To address the issue of bearer token theft, DPoP (RFC 9449) is emerging as a solution. It binds the JWT to a specific private key held by the client, ensuring that a stolen token cannot be used by an attacker unless they also possess the client's private key.

Summary Table: JWT vs. Stateful Sessions

Feature Stateful Sessions JWT (Stateless)
Revocation Immediate Delayed (until exp) or requires state
Database Load High (lookup per request) Low (cryptographic verification)
Scalability Requires shared cache (Redis/DB) Highly scalable (distributed verification)
Primary Risk Session Hijacking Token Theft / XSS (if in localStorage)
Best Use Case Browser-based UI sessions Microservices / API-to-API auth

Sources