Session vs Token Based Auth
Updated June 3, 2026Once a user proves who they are, your system needs a way to remember that across subsequent requests. HTTP is stateless — each request is independent, with no memory of previous requests. So how do you maintain a "logged in" experience?
There are two fundamentally different answers: session-based auth and token-based auth. The difference comes down to one question: who holds the state?
Session-based auth — login creates server-side session in Redis, session ID in cookie
Session-Based Auth (Server Holds State)
In session-based auth, the server is responsible for remembering the user's identity.
The user logs in with credentials. The server verifies them, creates a session record in a store (with a session ID, user ID, and expiry), and returns the session ID as a cookie:
Set-Cookie: session_id=abc123; HttpOnly; Secure; SameSite=StrictEvery subsequent request automatically includes the cookie; the server looks it up to identify the user.
The Session Store
For a single-server app, sessions can live in memory (or on disk). But as soon as you scale to multiple servers, you have a problem: if the user's session is on Server A, and the next request hits Server B, Server B doesn't know who they are.
Solutions:
- Sticky sessions: load balancer routes the user to the same server every time. Works, but breaks during deployments and server failures.
- Shared session store: all servers read from a shared store, typically Redis. This is the standard approach. Redis is fast enough that the lookup adds only a few milliseconds of overhead.
The key strength is instant revocation: need to log a user out immediately? Delete their session from the store. Their next request will fail authentication. This is critical for security-sensitive use cases: fraud detected, account suspended, password changed. Smaller requests are a secondary benefit. The client only sends a short session ID (32-64 characters) while the server holds all the state. Battle-tested is another way to describe the security model. Session-based auth has been the standard for web applications for 30 years and is well-understood.
The tradeoffs: the server must maintain and query a session store for every authenticated request, adding infrastructure complexity and a potential latency overhead (stateful). Cookies have same-origin restrictions, so a mobile app or a single-page app on a different domain will find them awkward (cross-origin limitations). The session store also becomes a shared dependency. If Redis goes down, everyone gets logged out, so you need to make it highly available (scaling).
When multiple servers need to share session state, what is the standard approach?
Token-based auth — server stateless, JWT verified by signature on each request
Token-Based Auth (Client Holds State)
In token-based auth, the client holds the state. The server is stateless.
The user logs in with credentials. The server verifies them and generates a signed token (typically a JWT) encoding the user's identity and any relevant claims, then sends it to the client. The client stores the token (localStorage, sessionStorage, or an in-memory variable) and includes it in the Authorization header of every subsequent request:
Authorization: Bearer <token>The server verifies the token signature and reads the claims — no database lookup needed. The token itself carries the user's identity, and the cryptographic signature confirms it is legitimate.
In token-based auth, the server must perform a database lookup on every authenticated request to verify the user's identity.
The core advantage is statelessness: each server can verify a token independently without talking to a shared store, so the system scales horizontally without shared infrastructure. Cross-origin use is natural — tokens in the Authorization header work across any origin, making them a good fit for APIs consumed by mobile apps, single-page apps, or third-party clients. You can also embed user roles, permissions, and other data directly in the token (flexible claims), and a single token can be passed between internal services without requiring each service to call a central auth endpoint (microservices-friendly).
The fundamental problem is no instant revocation. JWTs are valid until they expire. If a user changes their password, gets compromised, or their account gets suspended, you cannot immediately invalidate their token without some kind of server-side state (a blocklist) — which re-introduces statefulness. The standard mitigation is short expiry times (15-60 minutes) combined with refresh tokens — a longer-lived token (7-30 days) stored in an HttpOnly cookie, exchanged for a new short-lived access token. If you need to revoke access, you delete the refresh token from the server.
Larger requests are a minor consideration. A JWT with a few claims is typically 200-400 bytes per request versus a 32-character session ID, negligible in most cases. Token storage on the client has no perfect answer: localStorage is accessible to JavaScript (XSS-vulnerable), while HttpOnly cookies solve this but reintroduce cookie complexity. This is covered in the JWT chapter.
What is the standard mitigation for the lack of instant revocation in JWT-based auth?
Side-by-Side Comparison
| Session-Based | Token-Based (JWT) | |
|---|---|---|
| State held by | Server | Client |
| Revocation | Instant | Requires blocklist or short expiry |
| Scalability | Needs shared session store | Naturally stateless |
| Cross-origin APIs | Awkward | Natural fit |
| Server lookups | Every request | Only on refresh |
| Standard transport | Cookie | Authorization header |
| Typical use case | Traditional web apps | SPAs, mobile apps, APIs, microservices |
Token-based auth is a better fit than session-based auth for APIs consumed by mobile apps across different origins.
When to Use Each
Choose session-based auth when:
- Building a traditional server-rendered web app (Next.js with server-side rendering, Rails, Django)
- You need instant revocation (banking, healthcare, high-security applications)
- Your users are only on web (cookies are a natural fit)
- You're fine with managing a Redis session store
Choose token-based auth when:
- Building a public API consumed by mobile apps or third-party clients
- Building a microservices architecture where services need to verify identity without a central auth call
- Your frontend is a single-page app on a different domain than your API
- You want stateless, horizontally-scalable auth
The modern hybrid: Many production systems use both. A Next.js app with server-side rendering uses session cookies for the web frontend (secure, HttpOnly, easy to revoke). The same backend issues JWTs for the mobile app and third-party API access. Different clients, different auth mechanisms, same underlying identity system.
Which scenario best justifies choosing session-based auth over token-based auth?
Summary
Session-based auth puts state on the server — great for traditional web apps where you need instant revocation and users are on the browser. Token-based auth puts state on the client — great for APIs, mobile apps, and microservices where statelessness and cross-origin flexibility matter.
The choice isn't dogmatic. Understand the tradeoffs and pick the one that fits your constraints. When in doubt about revocation requirements (healthcare, finance, anything with legal exposure), lean toward sessions with a proper shared store — the ability to instantly terminate a session is worth the operational overhead.
Saved on this device only
Sign in to sync progress across devices