Statelessness

Fundamentals Security Notes Jan 6, 2025 JAVASCRIPT

Definition

Every time you walk into a bank branch, you show your ID. You do not expect the teller to remember you from last week and just hand over cash. This is statelessness in action - each interaction is complete and self-contained, requiring all necessary information to be presented again. In API design, statelessness means every request contains everything needed to process it, with the server remembering nothing between requests.

This might seem inefficient at first. Why should you prove who you are on every single request? Why can not the server just remember? The answer lies in scale and reliability. When a server stores information about each client (called “state”), it becomes tied to that specific client. If you have millions of users, storing state for each one consumes massive resources. Worse, if that server crashes, all that state is lost. If you need to add more servers to handle load, you have to figure out how to share or synchronize state between them.

Stateless design elegantly sidesteps these problems. Any server can handle any request because all necessary information comes with the request itself - usually in the form of a token. Need more capacity? Just add servers. One server crashes? Other servers keep working. Need to deploy an update? Restart servers one by one without affecting users. This is why REST APIs and most modern web services embrace statelessness, even though it means including authentication information with every single request.

Example

JWT-based APIs: When you are logged into a web application using JWTs, your browser sends the token with every API request. The server does not remember that you logged in five minutes ago - it verifies your token fresh each time. If you delete the token from your browser, it is as if you never logged in.

CDN and caching: Content Delivery Networks work because requests are stateless. When you request an image, any CDN server worldwide can serve it without needing to know your history. This is why websites load fast no matter where you are.

Load-balanced web servers: Large sites like Netflix have thousands of servers. Your requests might hit different servers each time, but it does not matter - each request is self-contained. The servers do not need to share information about you.

Cloud functions (AWS Lambda, etc.): Serverless computing is only possible because requests are stateless. A new function instance spins up, handles your request, and disappears. There is nowhere to store state even if you wanted to.

Analogy

The Different Bank Teller: Every time you visit the bank, you might get a different teller. You do not expect them to know your account details from memory - you present your ID, and they look up what they need. Stateless APIs work exactly this way: every request shows its “ID” (token), and the server looks up what it needs.

The Toll Booth: At a toll booth, you pay for your crossing. The toll booth does not remember that you paid yesterday or that you are a frequent driver. Each crossing is a complete, self-contained transaction. Stateless APIs treat each request the same way.

The Vending Machine: A vending machine has no memory of your previous purchases. Every transaction requires inserting money and making a selection. It does not know you bought chips yesterday or that you are on your third soda today. Each interaction is independent.

The Library Returns Desk: When you return a library book, you bring the book and your card. The librarian does not remember checking it out to you - they scan everything fresh. Each interaction includes all necessary information.

Code Example


// Stateless requests - each includes auth token
GET /api/orders/456
Authorization: Bearer eyJhbGc...

GET /api/orders/789
Authorization: Bearer eyJhbGc...

// Stateful (anti-pattern in REST)
POST /api/login  // Server creates session
GET /api/orders/456  // Server remembers you're logged in
GET /api/orders/789  // Still remembers

// Proper stateless design
const token = jwt.sign({ userId: 123 }, secret, { expiresIn: '1h' });
// Client includes token in every request
headers: { 'Authorization': 'Bearer ' + token }

Security Notes

SECURITY NOTES

CRITICAL: Stateless architecture improves scalability. Don’t store client state on server.

Stateless Design:

  • Each request self-contained: All data in request
  • No server-side session: State not stored on server
  • Token-based: Use tokens to carry state
  • Idempotent: Operations repeatable without state

Token-Based State:

  • JWT tokens: Carry user state in token
  • Signed tokens: Cannot be forged without key
  • Expiration: Tokens expire after time
  • User data: Include necessary data in token
  • Verification: Server verifies token signature

Advantages:

  • Scalability: No session affinity needed
  • Load balancing: Easy to distribute across servers
  • Horizontal scaling: Add servers without session migration
  • Redundancy: Failure of one server doesn’t lose sessions
  • Performance: No session lookup needed

Disadvantages:

  • Token size: Tokens larger than session IDs
  • Revocation: Harder to revoke tokens
  • Payload size: Each request carries all state
  • Token compromise: Stolen tokens valid until expiration

Implementation:

  • Use JWTs: Standard format for tokens
  • Short expiration: Keep token lifetime short
  • Refresh tokens: Use refresh tokens for long-term access
  • Secure storage: Store tokens securely on client
  • HTTPS mandatory: Always use HTTPS

Pitfalls:

  • Server-side state: Defeats purpose of statelessness
  • Session stickiness: Forces specific server (breaks scaling)
  • Cookies with state: Defeats statelessness
  • Caching: Cached state becomes inconsistent

Standards & RFCs