Tags: web-dev concept

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

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=Lax covers 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