Why authentication needs a system-level design, and when to choose which
Every request must answer two questions: who is this (authentication) and what may they do (authorisation). With one server, the answer lives in that server's memory. With many servers, several services, mobile apps and third parties, you need a design that works everywhere and survives theft and mistakes.
It gives you two things interviewers always ask about:
- Security: credentials are protected, stolen tokens can be limited or revoked, and each request is checked.
- Scalability and availability: any server can verify a request without a slow shared lookup, and a login system outage does not stop every request.
Decisions to make:
- How the user proves who they are: password, passkey, one-time code, single sign-on.
- How the system remembers them: a server-side session or a signed token.
- How services trust each other: tokens passed along, or mutual TLS between services.
- Where permission checks happen: at the gateway, in each service, or in a central policy service.
Skip building it yourself when:
- A managed identity provider meets your needs. Storing passwords and implementing OAuth is easy to get wrong.
Try it
A user logs in and makes requests. Change how the login is remembered, then change the situation.
Authentication and Authorisation at System Level
Step 1 of 4 · Press Space to play, arrow keys to stepInitial state. A user logs in, then makes requests. Two servers sit behind a load balancer, and the system has to recognise the user each time.
- tick:
- 0
- valid users refused:
- 0
- attacker requests accepted:
- 0
- extra logins forced:
- 0
1 tick = one step of the simulation.
Things to try:
- Run Session in one server's memory with the next request lands on a different server. The user is logged out.
- Switch to a shared store and a signed token and note that both work on any server.
- Choose A token is stolen, then the user logs out for each. A session ends at once, but a signed token stays valid until it expires.
- The tick counts are illustrative. The simulation uses a token lifetime of 8 ticks, and the accepted-request counter only shows that the attacker keeps getting in after logout, not an exact real-world number.
- The simulation does not show the recommended design, short-lived access tokens with rotating refresh tokens. Read the table below and compare the damage window: minutes instead of the full token lifetime.
Ways to remember a login
| Approach | How it works | Good when | Weakness |
|---|---|---|---|
| Session in server memory | The server keeps the session and sends an ID in a cookie | One server, prototypes | Tied to one server, lost on restart |
| Session in a shared store | The session lives in Redis or a database that all servers read | Web apps with many servers, need instant revocation | A lookup per request, and the store must be available |
| Signed token (JWT) | The server signs a token with the user's identity and expiry. Any server can verify it with a key | Many services, mobile apps, no shared lookup | Hard to revoke before expiry, tokens can be large |
| Opaque token plus introspection | A random token that a central service looks up | Strong control and revocation | A call to the identity service per request (can be cached) |
| Access plus refresh tokens | A short-lived access token, and a longer-lived refresh token to get new ones | Mobile and single-page apps | Refresh tokens need careful storage and rotation |
Words used on this page
- HttpOnly cookie: a cookie that page scripts cannot read, which limits theft through script injection.
- SameSite cookie: a cookie the browser does not send on most cross-site requests, which helps against CSRF.
- Issuer and audience: who created the token (
iss) and which service it is meant for (aud). A service must reject tokens meant for someone else. - CSRF: a malicious site makes the browser send a request with your cookie. Use SameSite cookies and CSRF tokens for state-changing requests.
Sessions vs tokens
- Sessions keep state on the server side and put a random ID in the cookie. Revocation is easy: delete the session. The cost is a lookup on every request and a store that must stay available.
- Signed tokens carry their own proof, so a service verifies the signature and expiry with no lookup. The cost is revocation: the token stays valid until it expires unless you keep a blocklist (which brings back a lookup) or keep lifetimes very short and use refresh tokens.
Many systems use both: short-lived signed access tokens, and a revocable refresh token or session behind them.
Which key signs the token
- Shared secret (HS256): one secret signs and verifies. Every service that verifies tokens must hold the secret, so any of them could also forge tokens. Fine for one service, risky across many.
- Key pair (for example RS256, ES256 or EdDSA): the identity service signs with a private key. Other services verify with the public key, which is published at a known address as a key set (JWKS) and cached. A service that only verifies cannot forge tokens.
Example 1 uses HS256 only because it needs no libraries.
How login and requests work
- The user sends credentials (or uses a passkey or single sign-on). The server checks them. Passwords are stored only as slow, salted hashes (for example Argon2, bcrypt or scrypt).
- The server issues a session ID or an access token (and maybe a refresh token) and sets it in a secure, HttpOnly cookie or returns it to the app.
- Each request carries the credential. The service verifies it: look up the session, or check the token's signature, expiry, audience and issuer.
- Authorisation follows: does this user have a role or permission for this action on this resource? Check on the server, never only in the client.
- When an access token expires, the app uses the refresh token to get a new one. Refresh tokens are rotated, so a stolen one is detected when both copies are used.
- On logout, or on a security event, the session is deleted, the refresh token is revoked, and any blocklist is updated.
- Between services, pass the user's token or use a service identity with mutual TLS, and check permissions in each service.
OAuth 2.0, OpenID Connect and SAML
- OAuth 2.0 lets an app get limited access to a resource on a user's behalf, without the user's password. It is about authorisation (access tokens with scopes).
- OpenID Connect (OIDC) adds an identity layer on top of OAuth 2.0. It returns an ID token that says who signed in. This is what "Sign in with" buttons use.
- SAML is an older XML-based standard for single sign-on, common in company systems.
- For browser and mobile apps, use the authorisation code flow with PKCE: the app sends the user to the identity provider, gets a one-time code back, and exchanges it for tokens along with a secret created for that attempt. This stops a stolen code from being used.
Authorisation models
| Model | How it decides | Good when | Weakness |
|---|---|---|---|
| Roles (RBAC) | The user has roles, and roles have permissions | Clear job types | Role explosion, cannot say "only their own orders" |
| Attributes (ABAC) | Rules over user, resource and context | Fine-grained rules | Harder to test and explain |
| Central policy service | Services ask one policy engine | Same rules in many services | An extra call, and a new dependency to keep up |
Whichever you choose, the service that owns the data makes the final check.
Authentication design vs the alternatives
| Concern | Shared sessions, or short-lived tokens | Server memory sessions | Long-lived static tokens |
|---|---|---|---|
| Works on any server | Yes | No | Yes |
| Instant revocation | Sessions yes, tokens by blocklist | Yes | No |
| Lookup per request | Sessions yes, tokens no | None | None |
| Damage if stolen | Limited by expiry | Until logout | Unlimited |
| Complexity | Medium | Low | Low |
| Best for | Production systems | One server | Never for users |
Use shared sessions or short-lived tokens with refresh in production. Server-memory sessions are for prototypes.
Avoiding a new single point of failure
- Session store: replicate it, and decide what happens when it is down (fail closed for sensitive actions).
- Identity provider: cache public keys and token checks locally so a short outage does not stop every request.
- Signing keys: rotate them on a schedule and publish new keys before they are used, so old tokens remain valid until they expire.
- Rate limits and lockouts: protect login from guessing, without letting an attacker lock out real users.
You accept extra infrastructure and careful key and token management in return for safer, scalable sign-in.
Common mistakes
- Storing passwords in plain text or with a fast hash. Use a slow, salted hash.
- Long-lived tokens in local storage that scripts can read. Prefer HttpOnly cookies or short lifetimes.
- Cookie sessions without CSRF protection. Use SameSite cookies and CSRF tokens for actions that change data.
- Trusting the client for permission checks. Check on the server for every request.
- Not validating token fields. Check signature, expiry, issuer and audience.
- Accepting the "none" algorithm or confusing key types in token libraries. Fix the allowed algorithms.
- No way to revoke. Decide how to cut off a stolen token before it happens.
- Rolling your own crypto or OAuth. Use a tested library or provider.
How to talk about authentication in an interview
- Separate authentication from authorisation, and say where each happens.
- Choose sessions in a shared store or short-lived signed tokens plus refresh tokens, and say why, including revocation.
- Know the difference between OAuth 2.0 (delegated access) and OpenID Connect (sign-in), and why PKCE is used.
- Mention hashing passwords, HTTPS, secure cookies, rate limiting login, and service-to-service identity.
- Name the trade-off: tokens scale without lookups but are harder to revoke, and sessions are easy to revoke but need a shared store.