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
- Server sends
Set-Cookieheader in response - Browser stores the cookie
- Browser sends cookie in
Cookieheader with subsequent requests to that domain - 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
- User logs in with credentials
- Server creates a session and generates a random session ID
- Server stores session data (user ID, permissions, etc.) keyed by session ID
- Server sends session ID in a cookie
- Browser sends session ID cookie with each request
- 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
- User submits username/password
- Server verifies credentials
- Server creates session, stores user info
- Server sets session cookie
- User is redirected to protected page
Authenticated Requests
- Browser automatically sends session cookie
- Server looks up session
- If valid, server knows who the user is
- Server returns personalized response
Logout
- User clicks logout
- Server destroys the session
- 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:
Prevention: Use HttpOnly attribute—JavaScript can't access the cookie.
Cross-Site Request Forgery (CSRF)
Attackers trick users into making requests while authenticated:
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):
- Works without cookies
- Session ID visible in logs, bookmarks, referrers
- Security risk—avoid this approach
Hidden Form Fields
State passed through forms:
- Limited to form submissions
- Useful for CSRF tokens
- Not suitable for general session management
Web Storage (Client-Side)
Modern browsers provide localStorage and sessionStorage:
- 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: