Authentication looks simple when an application has a few users.
A user enters an email and password, the server verifies the credentials, and the user is logged in.
But what happens when your application has millions of users, thousands of requests per second, multiple servers, mobile apps, and services distributed across different regions?
Authentication becomes a system-design problem.
You need to answer questions like:
- Where should authentication state be stored?
- How do multiple servers know that a user is logged in?
- Should you use sessions or JWTs?
- How should tokens expire?
- How do you revoke access?
- How does OAuth work?
- How do microservices verify users?
- How do you scale authentication across regions?
Let's break it down.
What Is Authentication?
Authentication answers one fundamental question:
"Who are you?"
For example:
User
↓
Email + Password
↓
Authentication Server
↓
Identity Verified
↓
Authenticated User
Authentication is different from authorization.
Authentication
Determines who the user is.
Who are you?
→ User 123
Authorization
Determines what the user is allowed to do.
What can User 123 access?
→ Read orders
→ Create orders
→ Cannot access admin panel
A scalable system usually needs both.
Basic Authentication Flow
A simple login system might work like this:
User
│
│ Email + Password
▼
Auth Server
│
│ Verify Credentials
▼
User Database
│
│ Valid
▼
Session / Token
│
▼
User
After login, the client needs some way to prove its identity on future requests.
This is where sessions and tokens come in.
Session-Based Authentication
With session-based authentication, the server creates a session after successful login.
For example:
User
↓
Login
↓
Server
↓
Create Session
↓
Session ID
↓
Browser Cookie
The browser might store:
session_id=abc123
On future requests:
User
↓
Cookie: session_id=abc123
↓
Server
↓
Session Store
↓
User Identity
The server uses the session ID to find the user's authentication state.
How Sessions Work at Scale
A single server can store sessions in memory:
User
↓
Server
↓
RAM
But this creates a problem when multiple servers are introduced.
Imagine:
Load Balancer
/ \
↓ ↓
Server 1 Server 2
│ │
Session A Session B
A user logs in through Server 1.
The session exists on Server 1.
The next request might go to Server 2.
Server 2 doesn't know about the session.
This is a problem.
Shared Session Store
One solution is to move sessions into a shared data store.
For example:
Load Balancer
/ \
▼ ▼
Server 1 Server 2
\ /
\ /
▼ ▼
Session Store
The session store could be a distributed in-memory database such as Redis.
Now every application server can access the same session state.
Request
↓
Any Server
↓
Shared Session Store
↓
User Session
This makes session-based authentication much easier to scale horizontally.
Advantages of Sessions
Sessions have several useful properties:
- Easy to invalidate
- Server controls authentication state
- Sensitive authentication data doesn't need to be stored directly in the browser
- Logout can invalidate the session
- Good fit for traditional web applications
But sessions also have a trade-off:
The server needs to maintain authentication state.
At very large scale, that shared state becomes an important infrastructure component.
What Is a Token?
A token is a piece of data that represents an authenticated identity or authorization.
Instead of storing all authentication state on the server, the client can present a token with its requests.
For example:
User
↓
Login
↓
Auth Server
↓
Access Token
↓
Client
Then:
Client
↓
Authorization: Bearer <token>
↓
API Server
↓
Validate Token
↓
Request Allowed
Tokens are commonly used in APIs, mobile applications, and distributed systems.
JWT Authentication
One popular token format is JWT (JSON Web Token).
A JWT typically contains information such as:
Header
Payload
Signature
Conceptually:
JWT
├── Header
├── Payload
└── Signature
The payload might contain claims such as:
{
"sub": "user123",
"role": "user",
"exp": 1780000000
}
The token is signed so the server can verify that it was issued by a trusted authority and hasn't been modified.
JWT Authentication Flow
A simplified JWT flow looks like this:
User
↓
Login
↓
Authentication Server
↓
JWT
↓
Client
↓
API Request
↓
Authorization: Bearer JWT
↓
API Server
↓
Verify Signature
↓
Allow Request
One major benefit is that the server doesn't necessarily need to look up a session for every request.
Sessions vs JWT
The difference can be summarized like this:
| Sessions | JWT |
|---|---|
| Server maintains session state | Token carries claims |
| Session ID sent by client | JWT sent by client |
| Easy revocation | Revocation requires additional strategy |
| Requires shared session storage at scale | Can be validated independently |
| Common for web applications | Common for APIs and distributed systems |
| Server controls session state | Client carries the token |
Neither is universally better.
The right choice depends on the system.
Stateless Authentication
JWTs are often used to create a more stateless authentication layer.
For example:
Load Balancer
/ | \
▼ ▼ ▼
Server 1 Server 2 Server 3
│ │ │
└──── Verify JWT ─┘
Each server can independently validate the token.
There doesn't necessarily need to be a centralized session lookup for every request.
This can simplify horizontal scaling.
But "stateless" doesn't mean there is no authentication infrastructure.
You still need to manage:
- Token issuance
- Signing keys
- Expiration
- Refresh tokens
- Revocation
- Key rotation
- User sessions
Access Tokens and Refresh Tokens
A common authentication design uses two types of tokens.
Access Token
Used to access APIs.
Client
↓
Access Token
↓
API
Access tokens are usually short-lived.
Refresh Token
Used to obtain a new access token.
Refresh Token
↓
Authentication Server
↓
New Access Token
The flow becomes:
Login
↓
Access Token + Refresh Token
↓
Client
│
├── Access Token → API
│
└── Refresh Token → Auth Server
↓
New Access Token
Short-lived access tokens reduce the impact of a stolen token.
Why Not Make Access Tokens Last Forever?
Suppose an access token remains valid for 30 days.
If an attacker obtains it, they may be able to use it for the entire validity period.
Shorter expiration reduces this window.
For example:
Access Token
↓
Short Lifetime
↓
Expires
↓
Refresh Token
↓
New Access Token
The exact expiration strategy depends on the application's security and usability requirements.
What Is OAuth?
OAuth is a framework for delegated authorization.
A common example is:
"Continue with Google"
Instead of giving your application your Google password, the user authenticates with Google and grants the application permission to access specific information.
A simplified flow:
User
↓
Your Application
↓
OAuth Provider
↓
User Authentication
↓
Authorization
↓
Authorization Code
↓
Your Backend
↓
Access Token
OAuth is especially useful when applications need access to resources controlled by another identity provider.
OAuth vs Authentication
OAuth is primarily about authorization, not simply proving identity.
For user authentication, systems commonly use OpenID Connect (OIDC) on top of OAuth 2.0.
Conceptually:
OAuth
↓
Delegated Authorization
OIDC
↓
Authentication / Identity
This distinction is important when designing authentication systems.
Authentication in Microservices
Now imagine a system with multiple services:
API Gateway
│
┌───────────┼───────────┐
▼ ▼ ▼
User Service Order Service Payment Service
Should every service implement login and password verification?
Usually, no.
A better approach is to centralize identity management.
Identity Provider
│
▼
Access Token
│
▼
API Gateway
│
┌───────────────┼───────────────┐
▼ ▼ ▼
User Service Order Service Payment Service
Services can validate the authenticated identity and authorization information rather than each implementing its own login system.
Authentication at the API Gateway
An API Gateway can perform authentication before forwarding requests.
For example:
Client
↓
API Gateway
↓
Validate Token
↓
Authenticated?
│
┌┴─────────┐
No Yes
↓ ↓
401 Service
This provides a centralized entry point.
However, internal services should still be designed carefully rather than blindly trusting every request from the network.
Distributed Authentication
At large scale, authentication infrastructure itself may be distributed.
A simplified architecture could look like:
Users
│
▼
Global Routing
│
┌───────────┴───────────┐
▼ ▼
Auth Region A Auth Region B
│ │
▼ ▼
Auth Servers Auth Servers
│ │
└───────────┬───────────┘
▼
User / Identity Data
Now additional challenges appear:
- Regional availability
- Data replication
- Key management
- Token validation
- Session consistency
- Failover
- Clock synchronization
- Rate limiting
Authentication becomes part of the overall distributed-system architecture.
What Happens If an Authentication Server Goes Down?
Authentication is often a critical dependency.
If users cannot authenticate, they may not be able to access the application.
Therefore, authentication infrastructure should avoid having a single point of failure.
For example:
Load Balancer
/ | \
▼ ▼ ▼
Auth 1 Auth 2 Auth 3
│ │ │
└───────┼───────┘
▼
Shared Data
Multiple authentication servers can provide redundancy.
Health checks and failover mechanisms can route traffic away from unhealthy instances.
Token Validation at Scale
Suppose your application receives millions of API requests.
You don't want every request to perform an expensive remote authentication lookup if it can be avoided.
A common approach is to use signed tokens that services can validate locally.
Request
↓
Service
↓
Verify Token Signature
↓
Check Claims
↓
Allow / Reject
This reduces dependency on a centralized authentication lookup for every request.
However, services still need access to trusted signing keys.
Key Management
If JWTs or other signed tokens are used, signing keys become critical infrastructure.
A simplified flow:
Identity Provider
│
│ Signs Token
▼
JWT Token
│
▼
Application
│
│ Verify Signature
▼
Valid Token
Keys should be protected carefully.
Large systems may use mechanisms such as:
- Key rotation
- Key versioning
- Secure key storage
- Public/private key pairs
- Key distribution endpoints
The goal is to avoid making a single long-lived secret a permanent point of failure.
Logout and Token Revocation
Logging out sounds simple:
User → Logout
But with stateless tokens, there's an important question:
What happens to an access token that has already been issued?
If the token remains valid until expiration, simply deleting it from the client doesn't necessarily invalidate it everywhere.
Possible strategies include:
- Short-lived access tokens
- Refresh-token revocation
- Session tracking
- Token deny lists
- Token versioning
- Centralized authorization checks
The right approach depends on how quickly the system needs to revoke access.
Authentication Rate Limiting
Authentication endpoints are attractive targets for attackers.
For example:
POST /login
POST /signup
POST /forgot-password
POST /refresh-token
These endpoints should typically have appropriate protections such as rate limiting and abuse detection.
A simplified flow:
Login Request
↓
Rate Limiter
↓
Authentication
↓
Success / Failure
This helps prevent excessive login attempts and protects authentication infrastructure from abuse.
A Scalable Authentication Architecture
Putting the concepts together:
Users
│
▼
Load Balancer
│
▼
API Gateway
│
Token Validation
│
┌────────────────┼────────────────┐
▼ ▼ ▼
User Service Order Service Payment Service
│ │ │
└────────────────┼────────────────┘
│
Databases
Alongside the application:
Identity Provider
│
┌────────┴────────┐
▼ ▼
Access Tokens Refresh Tokens
This separates identity management from application business logic.
Common Authentication Mistakes
Some common architectural mistakes include:
- Storing passwords insecurely
- Making access tokens live too long
- Putting sensitive information into tokens
- Sharing authentication secrets carelessly
- Having a single authentication server
- Not planning for token revocation
- Ignoring key rotation
- Treating OAuth as the same thing as authentication
- Trusting internal services without proper controls
- Building authentication independently in every microservice
Authentication is security-critical infrastructure.
It should be designed accordingly.
How Should You Choose?
There isn't one authentication strategy that works for every system.
Small Traditional Web Application
A server-side session can be a simple and effective choice.
Browser
↓
Session Cookie
↓
Server
↓
Session Store
Mobile or API-Heavy Application
Token-based authentication may be more appropriate.
Client
↓
Access Token
↓
API
Distributed Microservices
A centralized identity provider with signed access tokens can work well.
Identity Provider
↓
Access Token
↓
API Gateway
↓
Microservices
Social Login
OAuth + OpenID Connect is commonly used.
Application
↓
Identity Provider
↓
User Authentication
↓
Application
The Big Picture
Authentication at scale is not just about login forms.
It is about creating a reliable identity system that works across:
- Multiple servers
- Multiple services
- Multiple regions
- Web applications
- Mobile applications
- APIs
- Third-party identity providers
A simplified evolution might look like:
Simple App
↓
Sessions
↓
Shared Session Store
↓
Token-Based APIs
↓
Identity Provider
↓
Distributed Authentication
The architecture should evolve as the system's requirements grow.
Key Takeaway
There is no universal winner between sessions, JWTs, and tokens.
Each approach solves a different problem.
Sessions provide centralized server-side control.
JWTs can make token validation easier across distributed services.
Access and refresh tokens provide a flexible pattern for API authentication.
OAuth and OpenID Connect make delegated access and external identity providers possible.
And at large scale, authentication becomes distributed infrastructure that must be designed for security, availability, scalability, and failure.
Authentication isn't just about proving who the user is. At scale, it's about reliably proving identity across an entire distributed system.
Top comments (0)