← Back to all articles

Cookies vs Sessions: Difference and How They Work Together

SecurityHTTPBeginner

What each holds

A cookie is a small key-value pair in the browser, sent automatically on each request as the carrier of identity. A session is server-side user state; usually only a random session id goes into the cookie while the real data stays on the server.

Login flow

  1. The user logs in; the server verifies the password, creates a session, and stores user_id;
  2. It writes the session id into a cookie and returns it;
  3. On later requests the browser sends the cookie, and the server looks up the user by id.

JWT is not a session

A JWT encodes state into the token itself (with a signature), so the server may skip the lookup. Good for stateless services, but hard to revoke -- the token stays valid until expiry, unlike a session you can delete at will.

Cookie security flags

  • HttpOnly: blocks JS reads, defends against XSS token theft;
  • Secure: HTTPS only;
  • SameSite: limits cross-site sending, easing CSRF.

Real-world cases: three "logged out for no reason" bugs

  1. Lost login after a redirect: the cookie vanishes when returning from a third-party site, usually because SameSite=Lax blocked the cross-site request. If cross-site sending is genuinely required, set SameSite=None; Secure explicitly and serve over HTTPS.
  2. Same-named cookies overwriting each other: the apex domain and a subdomain each set a cookie with the same name; the browser sends both and the server reads the stale one. Set Domain and Path deliberately, or rename one.
  3. Logged out mid-session: sessions kept in process memory are invisible to other instances after scaling out. Move them to shared storage such as Redis, or switch to a stateless token.

FAQ

How long should a session id be? At least 128 random bits from a cryptographically secure source — never a sequence number or timestamp. Why rotate the session id on login? To stop session fixation: if the id is unchanged across login, an attacker can plant a known id and wait. Cookie or localStorage for tokens? A cookie with HttpOnly cannot be read by XSS and suits session credentials; localStorage is readable by any script. How do I refresh an expired JWT? Commonly a short-lived access token plus a longer refresh token, where the refresh token can be revoked and stored separately.

Try it

Generate a strong session secret: Password generator.

Choosing and scaling session storage

  • In-process memory: simplest on one node, but flaky across instances and needs migrating as soon as you scale out;
  • Shared store such as Redis: the common choice — set expiries, pick a serialisation format, pool connections, and plan degradation (reject new logins rather than letting everything through);
  • Database: suits auditing and long retention, but a query per request becomes a bottleneck, so add caching;
  • Encrypted cookie: keeps the server stateless at the cost of size limits and hard-to-revoke sessions;
  • Capacity planning: estimate active users times average session size, add peak headroom, and avoid saturating the store during a sale.

Expiry and renewal

Set both idle and absolute timeouts: the first expires after inactivity, the second caps total lifetime. Sliding renewal should extend the idle timeout but never the absolute one; for sensitive actions (password change, payment) re-authenticate rather than trusting the session.

Sessions across platforms and services

  1. Decide multi-device policy first: whether one account may be signed in on several devices and whether a new login evicts the old session shapes storage design — settle it before implementation.
  2. Pass identity explicitly between services: internal calls should carry the caller's identity rather than relying on shared session storage, or internal requests bypass authorisation.
  3. Keep sessions lean: store identifiers and necessary state, fetching details on demand; oversized sessions cost storage and raise per-request transfer and parsing.
  4. Tolerate stateless components: gateways and edge functions that cannot reach shared storage should receive limited information in a token instead of requiring session access.
  5. Monitor anomalies: one session appearing in two locations in a short window, or a spike in sessions per account, should alert and support fast invalidation.

The key is deciding up front who stores state and who verifies it — separating those makes scaling and hardening much easier.