TL;DR: Choose by revocation needs, who verifies, and the client type. Browser apps talking to their own backend: a server-side session in an HttpOnly, Secure, SameSite cookie, which is simple and instantly revocable. APIs verified by many services or third parties: short-lived bearer tokens (often JWTs) with revocable, rotated refresh tokens, and sender-constrained tokens (DPoP or mTLS) where theft is likely. Whichever you pick, the security work is storage, lifetime, rotation and revocation.
How to approach it
Frame the choice around four questions: who verifies the credential, how fast must revocation take effect, what kind of client holds it, and what happens if it is stolen. Then give the hardening checklist for each option.
A strong answer
Server-side session
Opaque cookie
HttpOnly, Secure, SameSite
Session store
lookup per request
Delete row = instant revocation
Outcome, safe: Best for browser apps
One backend verifies
Self-contained token (JWT)
Signed claims
verified by many services
No lookup
valid until expiry
Revocation needs short lifetimes or a deny list
Outcome, safe: Best for distributed APIs
Keep lifetimes in minutes
| Factor | Server session | Bearer token (JWT) |
|---|---|---|
| Verification | Lookup in a session store | Signature and claim check, no lookup |
| Revocation | Delete the record: immediate | Wait for expiry, or add denylist or introspection |
| Theft impact | Usable until the session ends; contents not exposed | Usable anywhere until expiry; claims readable |
| Best for | First-party browser apps | APIs, cross-domain, many verifying services |
Securing sessions. Random IDs of at least 128 bits from a cryptographic generator; regenerate on login and privilege change (prevents fixation); cookies with HttpOnly, Secure, SameSite=Lax or Strict, and the __Host- prefix; idle and absolute timeouts; server-side logout that deletes the record; CSRF protection for state-changing requests even with SameSite.
Securing tokens. Access tokens of minutes, not days; refresh tokens stored server-side or in secure platform storage, rotated on each use with reuse detection, and revocable; validate signature with a fixed algorithm, plus issuer, audience, expiry and scopes; never put secrets in JWT claims (they are readable); keep tokens out of URLs and logs; and bind tokens to the client's key with DPoP (RFC 9449) or mTLS (RFC 8705) for high-risk clients.
Browser single-page apps. Tokens in localStorage are readable by any injected script. A backend-for-frontend pattern keeps tokens on the server and gives the browser only a session cookie, combining the API-friendliness of tokens with the safer browser storage of sessions.
Agents and services. Agents hold tokens on servers, in memory and sometimes in tool configurations, where leakage through logs and traces is common. Short lifetimes, narrow scopes and sender constraints matter more here than for a human's browser.
What interviewers probe next
- "A user reports their account was compromised. How fast can you cut off access?" With sessions, immediately; with JWTs, revoke refresh tokens now and accept access tokens until expiry, which is why lifetimes should be minutes.
- "Why does refresh token rotation with reuse detection help?" If an old refresh token is used after rotation, someone copied it; revoke the whole token family.
- "Is SameSite enough to stop CSRF?" It stops most cases, but not same-site attackers (subdomains) or every browser behaviour, so keep CSRF tokens on sensitive actions.
What if?
What if · interview follow-ups
Hold your answer as the constraints change
A web app is moving from server-side sessions in Redis to self-contained JWTs so it can scale horizontally, and wants to know what it gives up.
Start here
What do server-side sessions do well?
How fast can you log a user out?
A random session ID in an HttpOnly, Secure, SameSite cookie maps to state on the server. It is simple, keeps data off the client and is instantly revocable: delete the session and the user is logged out everywhere.
Carry it forwardServer sessions are simple and instantly revocable.
Weak answerAssuming sessions cannot scale.
Constraint changes
What changes with self-contained JWTs?
What happens when you need to revoke one?
Any service can verify the token without a lookup, which helps distributed APIs. But a valid token stays valid until it expires, so revocation is hard, and claims in the token can become stale. Lifetime, rotation and revocation become the main work.
Carry it forwardSelf-contained tokens trade revocation for lookup-free checks.
Weak answerIssuing long-lived JWTs for browser sessions.
Constraint changes
Is scaling a good reason to switch here?
What actually limits scale today?
Usually not. A shared session store such as Redis already scales horizontally for most apps. For a browser app talking to its own backend, server-side sessions remain the better default. Tokens fit APIs verified by many services or third parties.
Carry it forwardChoose by revocation needs and verifiers, not fashion.
Weak answerRewriting authentication to solve a non-problem.
Constraint changes
If tokens are used, how do you limit theft damage?
How long is a stolen token useful?
Short-lived access tokens, rotated refresh tokens with reuse detection, revocation for refresh tokens, and sender-constrained tokens (DPoP or mTLS) where theft is likely. Store tokens where scripts cannot read them, for example behind a backend-for-frontend.
Carry it forwardShort lifetimes, rotation and binding limit token theft.
Weak answerStoring tokens in localStorage.
Constraint changes
What if a user's role changes or their account is disabled?
When does the change take effect?
With sessions, update or delete the server state and it applies immediately. With tokens, the old claims persist until expiry unless services check a revocation list or current permissions. Plan this explicitly for admin changes and account disablement.
Carry it forwardPlan how permission changes reach existing tokens.
Weak answerRelying on token claims as current truth.
Now defend it
What would you recommend?
Keep server-side sessions in secure cookies for the browser app, since a shared store scales. Use short-lived tokens with rotated, revocable refresh tokens and audience checks for APIs verified by multiple services, sender-constrain high-value tokens, keep tokens out of script-readable storage, and plan how revocation and permission changes take effect.
How it's scored
Weak: "JWTs are better because they are stateless," with no revocation or storage discussion.
Hire: Compares the two on revocation and theft, and lists cookie and token hardening.
Strong Hire: Chooses by context, covers refresh rotation, backend-for-frontend and sender-constrained tokens, and applies it to agents.
Common mistakes
- Day-long access tokens with no revocation path.
- Tokens in localStorage on XSS-prone apps.
- Secrets or personal data in JWT claims.
- Logging authorization headers.