A session management system maintains state across stateless HTTP requests — tracking who a user is across page loads without requiring re-authentication on every request. The design must handle session creation, validation, expiry, storage at scale, and security concerns (hijacking, fixation, CSRF).
Session Storage Options
Cookie-based (stateless JWT): the entire session state is encoded in a signed JWT stored in a cookie. The server validates the signature — no server-side storage required. Fast, horizontally scalable. Downside: cannot revoke a session before expiry (the JWT is valid until its exp claim). Logout is client-side only — the server cannot invalidate a stolen JWT. Server-side session store: a random session_id is stored in the cookie; the session data (user_id, roles, last_activity) is stored server-side (Redis or database). Allows instant revocation (delete the session record). More infrastructure required. Hybrid: short-lived JWT (15 minutes) for stateless validation + refresh tokens stored server-side for revocation control. This is the most common production pattern for APIs.
Redis Session Store
Redis is the standard session store at scale. Session creation: generate a cryptographically random session ID (128 bits, base64 encoded). Store: HSET session:{session_id} user_id {uid} created_at {ts} last_activity {ts} ip {ip}; EXPIRE session:{session_id} {ttl_seconds}. Session validation: GET session:{session_id} — if exists and not expired, valid. Update activity: HSET session:{session_id} last_activity {now}; EXPIRE session:{session_id} {ttl_seconds} — sliding expiry resets on each request. Session revocation: DEL session:{session_id}. List all sessions for a user (for “log out all devices”): maintain a secondary SET user_sessions:{user_id} containing session IDs. When revoking all: SMEMBERS user_sessions:{user_id} → DEL each session ID → DEL the set.
Security: Session Fixation and Hijacking
Session fixation: an attacker tricks a user into using a session ID controlled by the attacker. Prevention: always generate a new session ID on login, even if the user had an anonymous session. Regenerate session IDs on privilege escalation (anonymous → authenticated, regular user → admin). Session hijacking: an attacker steals a valid session ID via XSS or network eavesdropping. Prevention: (1) HttpOnly cookie flag — prevents JavaScript from reading the cookie, blocking XSS theft. (2) Secure flag — cookie only transmitted over HTTPS. (3) SameSite=Strict or SameSite=Lax — prevents CSRF by restricting cross-origin cookie sending. (4) Bind sessions to IP or user agent (optional, but breaks legitimate IP changes like VPN). (5) Short session TTLs for sensitive operations — require re-authentication for high-risk actions regardless of session validity.
Distributed Session Consistency
With multiple web servers, all servers must read from the same session store. Do not use sticky sessions (routing a user to the same server) — this creates uneven load and loses sessions when servers restart. Centralized Redis session store allows any server to validate any session. For global deployments: replicate session data across regions with eventual consistency — a user whose session was created in US-East can be validated in US-West after ~100ms replication lag. Active-active Redis Geo-Replication (Redis Enterprise) or a globally replicated store (Cassandra, DynamoDB global tables) handles this. For truly global consistency: accept slight latency by routing session validation to the origin region, or use short-lived JWT tokens that don’t require server-side lookup for the common case.
Session Expiry Strategies
Two expiry models: Absolute expiry: session expires N hours after creation regardless of activity (e.g., 24-hour sessions). Simpler — set TTL at creation, never extend. Appropriate for high-security contexts (banking: sessions expire after 15-30 minutes absolute). Sliding expiry: TTL resets on each request (e.g., expire after 30 minutes of inactivity). Better UX — active users stay logged in. Reset the TTL on every authenticated request. Implement a maximum session lifetime as a ceiling on sliding expiry (e.g., max 7 days regardless of activity — forces periodic re-authentication). Notify users before session expiry for long-running operations (show “Your session expires in 5 minutes — extend?” dialog).