Session Management Best Practices: Cookies, Tokens, and Rotation
Stateful sessions vs. stateless tokens, cookie security flags, refresh token rotation, idle and absolute timeouts, and how to revoke access when it matters.
Logging a user in is the easy part. Keeping them logged in — securely, across requests, devices, and tabs, while still being able to kick them out instantly — is where most of the real design work lives. This article covers the decisions that make up good session management.
Stateful sessions vs. stateless tokens
There are two broad approaches to remembering that a user is authenticated.
Stateful (server-side) sessions. The server stores session data (in a database, Redis, etc.) and gives the client an opaque session ID, usually in a cookie. Every request looks the session up server-side.
- Pros: trivial revocation (delete the row), no sensitive data on the client, easy to inspect.
- Cons: requires a session store and a lookup on every request.
Stateless tokens (JWTs). The server issues a signed token containing the claims. No server-side lookup is needed — the signature proves validity.
- Pros: scales horizontally with no shared session store, fast to verify.
- Cons: revocation is hard. A valid token is valid until it expires, full stop.
In practice, the strongest designs combine both: short-lived stateless access tokens for fast per-request checks, plus a long-lived, revocable refresh token backed by server-side state. You get the performance of stateless verification and the control of server-side revocation.
Cookie security flags
If you store session identifiers or tokens in cookies — and you usually should — set these flags:
HttpOnly— the cookie can't be read by JavaScript, which neutralizes token theft via XSS.Secure— the cookie is only sent over HTTPS.SameSite— controls cross-site sending.Laxis a sensible default;Strictis tighter but breaks some cross-site navigation flows;None(which requiresSecure) is needed for legitimate cross-site contexts like embedded iframes.PathandDomain— scope the cookie as narrowly as the application allows.
Set-Cookie: session=...; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=900
Why HttpOnly cookies beat localStorage: tokens in localStorage are readable by any script on the page, so a single XSS bug exfiltrates them. An HttpOnly cookie is invisible to JavaScript, so the same bug can't steal it directly.
Access tokens and refresh tokens
The two-token pattern works like this:
- The access token is short-lived (often 5–15 minutes) and presented on each request. Because it expires quickly, a stolen access token has a small window of usefulness.
- The refresh token is long-lived, stored securely (ideally an
HttpOnlycookie), and used only to obtain new access tokens. It's tracked server-side so it can be revoked.
When the access token expires, the client silently exchanges the refresh token for a new access token. The user never notices.
Refresh token rotation
A long-lived refresh token is a juicy target, so harden it with rotation: every time a refresh token is used, issue a brand-new one and invalidate the old.
The payoff is theft detection. If an attacker steals a refresh token and uses it, the legitimate user's next refresh will present the now-invalidated old token. Detecting reuse of a rotated token is a strong signal of compromise — at which point you revoke the entire token family and force re-authentication.
1. Client refreshes with token A -> server issues token B, invalidates A
2. Attacker later replays token A -> server sees a used/invalid token
3. Server revokes the whole family -> both parties must log in again
Timeouts: idle vs. absolute
Two different limits, and you want both:
- Idle timeout — the session ends after a period of inactivity (e.g. 30 minutes). Protects unattended sessions.
- Absolute timeout — the session has a hard maximum lifetime regardless of activity (e.g. 7–30 days). Bounds how long a single login can last before re-authentication.
Sensitive operations (changing a password, payment details, deleting data) should additionally require step-up authentication — re-confirming identity even within a valid session.
Revocation: the feature you'll wish you had
At some point a user will report a lost laptop, or you'll detect a compromised account, and you'll need to end sessions right now. Build this in from the start:
- Maintain a server-side record of active sessions/refresh tokens so each can be revoked individually.
- Offer users a "sign out everywhere" action and a list of active sessions with device and location info.
- On password change, invalidate all existing sessions by default.
- Keep access tokens short-lived so that even pure-stateless revocation has a small ceiling on how long a revoked user stays authenticated.
Cross-tab and cross-device consistency
Users expect signing out in one tab to sign them out everywhere, and refreshing a token in one tab shouldn't break another. The storage event and the BroadcastChannel API let tabs coordinate session state. For multi-device consistency, server-side session records are the source of truth.
A practical default
For most web applications, a solid baseline is:
- Short-lived access token (5–15 min), long-lived rotating refresh token in an
HttpOnly,Secure,SameSitecookie. - Server-side session/token records for revocation.
- Idle timeout plus an absolute lifetime.
- "Sign out everywhere," active-session listing, and full invalidation on password change.
- Step-up auth for sensitive actions.
None of this is glamorous, but session management is where authentication quietly succeeds or fails. The systems users trust most are the ones that keep them logged in seamlessly — and can throw them out instantly the moment something's wrong.
Written by
Emilian GheoneaSenior Blockchain & Full-Stack Software Engineer. I build EmbedAuth — an embeddable authentication platform for SaaS — and write about the auth problems most teams hit too late.
Related articles
Authentication
What Is Embedded Authentication?
Embedded authentication keeps users in your product when they sign in, instead of bouncing them to a third-party domain. Here's how it works, what it changes, and the tradeoffs you sign up for.
May 12, 2026 7 minReadSecurity
Common Authentication Vulnerabilities and How to Prevent Them
Credential stuffing, broken session handling, JWT confusion attacks, account enumeration, and the other ways login systems get broken in production — plus the concrete fixes for each.
May 28, 2026 4 minReadOAuth & OIDC
How OAuth 2.0 Actually Works
OAuth 2.0 explained without the marketing copy — what the redirects are really doing, where the tokens come from, what PKCE protects against, and the parts the spec doesn't make obvious.
May 10, 2026 9 minReadSecurity
Protecting Auth Endpoints: Rate Limiting and Brute-Force Defense
How to design rate limiting for login, OTP, and reset endpoints — algorithms, what to key on, lockout strategies, and avoiding the traps that let attackers through or lock out real users.
Jun 12, 2026 4 minRead