Stateless Servers and Session Management
The server does not keep user data in its own memory, so any request can go to any server. The session lives either in Redis or in a token (JWT).
7.1 Why is it used?
- If the login session is in server-1's memory and the next request goes to server-2, the user will be logged out.
- Stateless servers can be freely added/removed. Auto-scaling and rolling deploys become easy.
- If the server crashes the user's session is not lost, as long as the session is outside (in Redis).
- The load balancer can spread traffic evenly without any restriction.
- Token-based auth (JWT) is a natural fit for mobile apps and microservices.
7.2 How it works
- 1.Stateful: req 1 -> LB -> Server-1 (session user42 in RAM); req 2 -> Server-2, which does not know the session -> user logged out!
- 2.Sticky session is a hack: uneven load, and server down = session gone
- 3.Stateless: the user's cookie holds only sid=abc; any server (Server-1 / Server-2) reads sid:abc -> user 42, cart from Redis
- 4.Any server, same session: the LB can spread traffic freely
- 1.1. OTP login: Mobile App -> Auth Service, which verifies the OTP and issues tokens
- 2.2. Tokens: access JWT 15 min + refresh token 30 days; the refresh token is stored in Redis/DB with the device ID, and blocked user IDs go in a denylist
- 3.3. 'Authorization: Bearer <JWT>' on every API call; any of the 500 stateless servers just verifies the signature (secret/public key), with no lookup in a session store; auto-scale +200 servers are ready instantly
- 4.4. After 15 min a new JWT comes from the refresh token
- 5.5. Logout from all devices: delete refresh tokens from Redis, and old JWTs expire on their own within 15 min at most; on fraud, put the user ID in the denylist to block immediately
JWT = header.payload.signature (alg RS256, the payload holds user_id: 42 and exp: +15 min, the signature is tamper-proof). If you keep it in a cookie use HttpOnly + Secure + SameSite
- Stateful vs Stateless: a stateful server remembers the previous request; in stateless every request carries its full identity (cookie/token) with it.
- Sticky Sessions (session affinity): the LB uses a cookie to always send the same user to the same server. Easy, but uneven load, and server down = session gone.
- Centralized session store: the session ID in the cookie, the data in Redis/Memcached. Any server reads from Redis.
- JWT (JSON Web Token): header.payload.signature. The user info is signed inside the token, the server only verifies the signature, no lookup in a store.
- JWT logout problem: the token stays valid until it expires, so use a short-lived access token (15 min) + refresh token (days) + denylist.
- Cookie security: HttpOnly (JS cannot read it), Secure (HTTPS only), SameSite (protects against CSRF).
- Keep the rest of the state outside too: file uploads in S3/Blob, cache in Redis, background jobs in a queue. Nothing local on the server.
- OAuth2 / OIDC: an identity provider like Google/Keycloak/Cognito issues the token, and apps only verify it.
7.3 Which tools can be used
| Tool | Type | How it is used |
|---|---|---|
| Redis | In-memory session store | User data under a session:<id> key with TTL; common with Spring Session and express-session. |
| Memcached | In-memory cache | A simple session cache, but no persistence/replication. If a node goes, the sessions on it go. |
| JWT libraries (jjwt, jsonwebtoken, PyJWT) | Token-based auth | Create a signed token at login and verify the Authorization: Bearer <token> header on every request. |
| AWS ALB / Nginx sticky sessions | Load balancer affinity | Send the user to the same target using the ALB stickiness cookie (AWSALB) or Nginx ip_hash/sticky. |
| Amazon ElastiCache / Azure Cache for Redis | Managed Redis | Managed, replicated Redis that is production-ready as a session store. |
| Keycloak / AWS Cognito / Auth0 | Identity provider | They handle login and issue OAuth2/OIDC tokens, so apps stay stateless. |
7.4 Comparison: Sticky Sessions vs Redis Session Store vs JWT
| Point | Sticky Sessions | Redis Session Store | JWT (stateless token) |
|---|---|---|---|
| Where the session data lives | In the server's memory | In central Redis | In the client's token (signed) |
| Speed | Fast, local memory | A ~1 ms Redis call on every request | Fast, only a signature verify |
| When a server goes down | Users of that server are logged out | No effect | No effect |
| Scaling | Uneven load, scale-in is hard | Easy, Redis also has to be scaled | Easiest, no shared store |
| Logout / revoke | Easy: delete the session | Easy: delete the Redis key | Hard: valid until expiry, needs a denylist |
| Complexity | Simplest | Medium: managing Redis HA | Medium: keys, refresh token, security |
| Best for | Legacy apps, a quick fix | Web apps with server-side sessions | Mobile apps, microservices, APIs |
7.5 When to choose which
- Sticky sessions: a legacy app you cannot change right now. As a temporary solution.
- Redis session store: a normal web app where you need instant logout/revoke and more data in the session.
- JWT: mobile apps, public APIs, microservices where each service verifies the user without a central lookup.
- Hybrid is common: a short-lived JWT access token + the refresh token/denylist in Redis.
7.6 Real-world example
Scenario: login in a payments app like Paytm/PhonePe
- The user logs in with an OTP; the auth service gives a JWT access token valid for 15 minutes and a refresh token valid for 30 days.
- The refresh token's record is stored in Redis/DB along with the device ID.
- On every API call the app sends 'Authorization: Bearer <JWT>'; any of the 500 servers verifies the signature and serves the request.
- Auto-scaling adds 200 new servers. They do not need any session and start taking traffic immediately.
- After 15 minutes the access token expires; the app gets a new access token using the refresh token.
- The user taps 'logout from all devices': refresh tokens are deleted from Redis, and old access tokens expire on their own within 15 min at most.
- If fraud is detected, the user ID can also be put in the denylist (Redis) to block them immediately.
7.7 Interview tips
- Say 'for horizontal scaling the app must be stateless' and explain the sticky vs Redis vs JWT trade-off.
- Mistake: putting sensitive data (password, PAN) in a JWT. The payload is only base64 encoded, not encrypted; anyone can read it.
- Mistake: setting a very long JWT expiry (30 days). If the token is stolen you cannot revoke it.
- Mistake: keeping the JWT in localStorage is an XSS risk. On the web an HttpOnly Secure cookie is better.
- Number: access token 15 min + refresh token 30 days; a Redis session lookup is ~1 ms per request.