Sessions and Tokens
Date: 2026-08-17
Two ways of remembering that a user logged in. Server-side sessions can be revoked instantly and need shared storage; tokens need no storage and cannot be un-issued — and that single difference decides which one fits.
A server-side session stores login state on the server and gives the browser only an ID to present; a token, usually a JSON Web Token (JWT), carries the login claims itself, signed so the server can verify them without a lookup.
HTTP is stateless, so every request must carry proof of a previous login. There are two mechanisms.
SERVER-SIDE SESSION TOKEN (JWT)
cookie holds an ID the token holds
the claims
state lives on the state lives in
server the token
lookup per request verify signature
per request
REVOKE INSTANTLY cannot revoke
until expiry
needs shared storage stateless
The trade, stated plainly
Sessions: the server holds the truth. Delete the record and the user is logged out immediately, everywhere. Cost is storage every instance can reach — usually Redis.
Tokens: the token is the truth, signed so it can’t be forged. Any server can verify it with no lookup. Cost is that you cannot take it back — a stolen token is valid until it expires, and “log out all devices” doesn’t work without adding back the state you removed.
The revocation problem is the deciding factor, and it’s routinely underweighted when JWTs are chosen for a session-shaped job.
What a JWT is
header.payload.signature
The first two segments are base64-encoded JSON — a header naming the algorithm, and a payload of claims:
{"alg": "HS256", "typ": "JWT"}
{"sub": "7", "exp": 1755432000}The signature covers both.
Base64 is encoding, not encryption. Anyone holding a JWT can read its contents. Never put anything sensitive in one — the signature stops modification, not reading.
Two failure modes worth knowing:
alg: none
older libraries accepted a token
claiming no algorithm. Always pin
the expected algorithm
confusing HS256 and RS256
a library that picks the algorithm
from the token lets an attacker
choose it
Cookie flags, which are the actual controls
Whichever mechanism you use, the cookie carrying it needs all of these:
HttpOnly JavaScript cannot read it
→ XSS cannot steal it
Secure HTTPS only
SameSite Lax sent on top-level
navigation — a good
default
Strict never sent cross-site
None always sent; REQUIRES
Secure
Path/Domain scope it as narrowly as
possible
Max-Age an expiry
HttpOnly is the one that matters most. It blocks XSS — cross-site scripting, where an attacker gets their JavaScript running on your page. A token in localStorage is readable by any script on the page — including a compromised third-party tag, which on a retail site is a realistic threat — Third-Party Scripts.
Storing tokens in localStorage to avoid cookies trades a CSRF problem for an XSS problem — cross-site request forgery, where another site causes an authenticated request from your user’s browser. XSS is the more common and more damaging of the two.
The pattern that works
ACCESS TOKEN short-lived, 5–15 min
carries claims
stateless verification
REFRESH TOKEN long-lived
stored server-side
REVOCABLE
exchanged for a new
access token
This gets both properties. Statelessness for the common case, revocation where it counts, and a stolen access token expires quickly. Rotate the refresh token on each use and detect reuse — a replayed refresh token means it was stolen, and the correct response is to invalidate the whole family.
Choosing
one application, one server or a shared
cache → SESSIONS. Simpler,
revocable, fine
many services needing to verify without
a shared store → TOKENS
mobile or third-party API clients
→ TOKENS
anything where instant logout matters
→ sessions, or
access + refresh
Default to server-side sessions for a normal web application. JWTs are frequently chosen for statelessness that isn’t needed, and the revocation cost is discovered later.
Other things to get right
- Regenerate the session ID on login. Otherwise session fixation — an attacker sets a known ID beforehand and inherits the authenticated session
- Expire on both idle and absolute time
- Invalidate every session on password change
- CSRF protection where cookies authenticate requests.
SameSite=Laxcovers most of it; a token is still the belt-and-braces answer for state-changing requests — Common Vulnerabilities - Log out means server-side invalidation, not just clearing the cookie