System Design: Designing Stateless Authentication
In a microservices architecture, you can't rely on server-side sessions (stored in memory/database) because every request might hit a different service instance. Stateless Authentication using JWT (JSON Web Tokens) is the industry standard.
1. How it works
- Login: User authenticates via username/password.
- Issue: The Auth Server generates a JWT, signs it with a secret key, and sends it to the client.
- Usage: The client sends the JWT in the header for every subsequent request.
- Verification: Services verify the signature using the public key. If the signature matches, the user is authenticated. No database lookup is needed.
2. Security: Signing & Expiry
- Signature: Always use asymmetric signing (RS256 or EdDSA). The Auth Server keeps the Private Key (to sign); Microservices keep the Public Key (to verify).
- Short-lived tokens: Tokens should expire in 15-60 minutes to limit the blast radius if stolen.
- Refresh Tokens: Use a longer-lived refresh token stored in an HTTP-only cookie to issue new access tokens.
3. The Revocation Challenge
JWTs are "stateless," meaning you can't easily "logout" a user before their token expires.
- Solution: Keep a Revocation List (a blacklist) in a fast distributed store like Redis. For every request, check if the token ID (jti) is in the Redis blacklist.
4. Access token vs refresh token boundary
A robust auth system separates responsibilities:
- short-lived access token for API authorization
- long-lived refresh token for session continuity
Refresh tokens should be rotated on every use and tied to device/session identifiers to detect theft or replay.
5. Key rotation and JWKS strategy
Signing keys must rotate periodically without downtime.
Best practice:
- expose public keys through JWKS endpoint
- include
kidin JWT header - allow overlapping old/new keys during rotation window
Services should cache keys with TTL and re-fetch on unknown kid.
6. Claims design and least privilege
JWT claims should be minimal and purpose-specific:
- subject (
sub) and tenant context - coarse role/scopes for authorization
- expiry and issued-at timestamps
Avoid overstuffing user profile data; large tokens increase bandwidth overhead and stale-claim risk.
7. Multi-service authorization pattern
Authentication and authorization are related but different:
- gateway verifies token integrity and baseline policy
- downstream services enforce fine-grained domain authorization
Do not centralize all authorization logic in one edge layer for complex domains.
8. Threat model considerations
Key risks:
- token theft from XSS/local storage leaks
- refresh token replay
- algorithm confusion or weak signature validation
- accepting tokens from wrong issuer/audience
Mitigations include strict iss/aud checks, HTTP-only secure cookies, CSP hardening, and anomaly detection.
9. Performance and reliability trade-offs
Stateless verification is fast, but revocation and introspection can reintroduce stateful dependencies.
Practical approach:
- local verification for most requests
- selective Redis revocation checks for sensitive scopes
- failover policy for revocation backend outages based on risk tier
Auth design is always a balance between security response speed and availability.
10. Observability checklist
Track:
- token verification failures by reason
- refresh success/failure rates
- revocation hit count
- suspicious geo/device token reuse
Security systems without telemetry turn incidents into blind forensics exercises.
Summary
Stateless auth is the key to scaling microservices. By moving the authentication state from the server to the client's token, you remove a major database bottleneck and make your services independently scalable.
