Back to the map

Module 04 · API fundamentals · Lesson 12 of 15

Sessions vs tokens

Two ways to remember a login: server-side sessions behind an opaque cookie, or signed tokens verified without a lookup. What each costs in storage, revocation and scaling, and the hybrid most real systems use.

CoreMust-knowMid 11 min Updated Nov 2026

Why it matters

After a user proves who they are, every later request has to carry that proof. How you carry it decides whether you need a shared session store, whether you can log someone out instantly, how many servers can verify a request, and which browser attacks you are exposed to. "Sessions or tokens" is really "where does the state live", and that is a scaling and security decision at once.

The idea

A session stores login state on the server, keyed by a random opaque id that the client holds, almost always in a cookie. Each request looks the id up to find the user. A token (typically a JWT, covered next) carries the state itself, signed by the server, so any server with the verification key can trust it without a lookup.

session (stateful)Clientsid cookiesidAPIlookupSession storeRedistoken (stateless)Clientsigned tokentokenAPIverify signature locally; no lookup
Sessions look up state on every request; tokens carry it and are verified locally. The session store is a shared dependency; the signing key is a shared secret.
 Server-side sessionsSelf-contained tokens
StateOn the server; client holds only an idIn the token; server holds the key
Per-request costOne lookup in a shared storeOne signature verification, no I/O
RevocationInstant: delete the sessionHard: token is valid until expiry unless you keep a deny list (which reintroduces state)
Horizontal scalingNeeds a shared store or sticky sessionsAny server with the key can verify
Cross-service useEach service must reach the storeToken can be passed downstream and verified anywhere
PayloadAnything, any size, privateSmall, visible to the client (signed, not encrypted)
Browser risksCSRF if cookie-based; mitigated with SameSite and tokensXSS if stored in JavaScript-readable storage; mitigated with HttpOnly cookies
Typical homeWeb apps with a single backendAPIs with many services, mobile clients, third-party access

Revocation is the real difference

Everything else is engineering, but revocation is a trade you cannot avoid. Sessions can be killed instantly because the server owns the state. A stateless token lives until it expires, so a compromised token or a banned user stays valid for its lifetime. The standard compromise is short-lived access tokens (5 to 15 minutes) plus a long-lived refresh token stored server-side: the access token is verified statelessly on every request, and revocation takes effect the next time the client refreshes. Instant revocation of access tokens needs a deny list checked per request, which is a small session store by another name.

Where to store it in a browser

Cookies with HttpOnly, Secure and SameSite=Lax or Strict are the safest home for either a session id or a token: JavaScript cannot read them, so an XSS bug cannot steal them, and SameSite blocks most CSRF. Storing tokens in localStorage is convenient and exposes them to any script on the page. Mobile and server clients keep tokens in secure platform storage and send them in an Authorization: Bearer header.

The hybrid most systems end up with

A session-like refresh token in an HttpOnly cookie or secure storage, exchanged for short-lived access tokens that services verify statelessly. The edge handles the exchange; internal services see only access tokens. This gives stateless scaling for the hot path and server-side control for revocation.

Trade-offs

Sessions are simple, revocable and private at the cost of a shared store that every server and service must reach. Tokens scale across servers and services and carry identity downstream at the cost of delayed revocation and a visible payload. Short expiry plus refresh tokens buys most of both, and adds the refresh flow and its own token store.

In an interview

Say where the state lives and how you revoke: "Short-lived JWT access tokens verified by each service with the public key, issued from a refresh token stored server-side, so logout and bans take effect within fifteen minutes and we can revoke instantly by deleting the refresh token." For a classic web app with one backend, saying "server-side sessions in Redis with an HttpOnly SameSite cookie" is equally strong and simpler.

Check yourself

A security team wants a banned user cut off within seconds, but the API uses stateless JWTs valid for 24 hours. What is the smallest design change that achieves it?

Sessions vs tokens · Backplane