Redis Session Storage

A session remembers who a visitor is between page loads. Websites store a small piece of data for each logged-in user, such as the user ID, role, and cart. Redis suits this job because reads are instant, expiry is built in, and many web servers can share the same sessions.

The Cloakroom Ticket Analogy

At a theater cloakroom, you hand over your coat and receive a numbered ticket. You keep only the ticket. When you return, the attendant uses the number to find your coat. A session works the same way. The browser holds a session ID, and Redis holds the data behind it.

  Browser                      Web Server                   Redis
  ┌──────────┐  cookie: abc9   ┌────────────┐  HGETALL     ┌─────────────────┐
  │ Holds ID │ ──────────────► │ Reads the  │ ───────────► │ session:abc9    │
  │ "abc9"   │                 │ cookie     │ ◄─────────── │ user_id = 1001  │
  └──────────┘                 └────────────┘  data        │ role    = admin │
                                                           └─────────────────┘

Why Not Store Sessions on the Web Server?

A site with several web servers behind a load balancer sends each request to any server. Memory on server 1 does not exist on server 2, so the user would appear logged out at random. A shared Redis store fixes this, because every server reads the same session.

  Request 1 ──► Server A ─┐
  Request 2 ──► Server B ─┼──► Redis (one shared session store)
  Request 3 ──► Server C ─┘

Creating a Session

Store each session as a Hash with an expiry. The key name carries a long random ID.

127.0.0.1:6379> HSET session:f3a9c1e7 user_id 1001 role "editor" cart_items 3
(integer) 3
127.0.0.1:6379> EXPIRE session:f3a9c1e7 1800
(integer) 1

The expiry of 1,800 seconds removes the session after 30 minutes.

Reading a Session

127.0.0.1:6379> HGETALL session:f3a9c1e7
1) "user_id"
2) "1001"
3) "role"
4) "editor"
5) "cart_items"
6) "3"

An empty reply means the session expired or never existed, so the app asks the user to log in again.

Sliding Expiry

Active users should stay logged in. Reset the timer on every request.

127.0.0.1:6379> EXPIRE session:f3a9c1e7 1800
(integer) 1
Timeline of a user:

  00:00  Login            → TTL set to 30 minutes
  00:10  Clicks a page    → TTL reset to 30 minutes
  00:25  Clicks a page    → TTL reset to 30 minutes
  00:56  No activity      → session expires 30 minutes after the last click

Updating and Ending a Session

127.0.0.1:6379> HINCRBY session:f3a9c1e7 cart_items 1
(integer) 4
127.0.0.1:6379> DEL session:f3a9c1e7
(integer) 1

Logging out deletes the key at once. The user's old cookie then points to nothing.

Security Rules for Session IDs

  • Generate IDs with a cryptographic random generator and make them long, such as 32 bytes.
  • Send the cookie over HTTPS only and mark it HttpOnly so scripts cannot read it.
  • Create a fresh session ID after login to block session fixation.
  • Avoid storing passwords or full card numbers in session data.

Listing a User's Sessions

Some sites let users see and end their active devices. Keep a Set of session IDs per user.

127.0.0.1:6379> SADD user:1001:sessions f3a9c1e7 b27d44a0
(integer) 2
127.0.0.1:6379> SMEMBERS user:1001:sessions
1) "f3a9c1e7"
2) "b27d44a0"

Remove stale IDs from the Set when sessions expire or when the user logs out.

Practical Example – Shop Login Flow

1. User submits the correct password.
2. Server creates session:f3a9c1e7 with HSET and EXPIRE 1800.
3. Server sends the ID to the browser in a secure cookie.
4. Each later request reads the session from Redis.
5. Each request resets the 30-minute timer.
6. User clicks Logout and the server runs DEL on the key.

Key Points

  • Redis stores session data and the browser stores only the session ID.
  • A Hash with EXPIRE models a session with a built-in timeout.
  • Resetting EXPIRE on each request creates sliding sessions.
  • Shared storage lets many web servers recognize the same user.
  • Use long random IDs and secure cookies.