Master JWT vs cookie-based auth, refresh token rotation, httpOnly cookie storage, OAuth 2.0, session management, and SSO. The complete guide to authentication architecture questions that appear in every senior frontend system design interview.
Authentication is fundamentally a trust problem: 'How does the server know the next request comes from the same user who logged in?' Cookie-based auth delegates this to the browser — cookies are automatically sent with every request. JWT-based auth hands the user a signed badge they carry themselves — stateless, portable, but impossible to revoke without extra infrastructure. The right choice depends on your threat model, your backend architecture, and whether you need cross-domain sessions.
The server creates a session record on login and returns a session ID as a cookie. On every request, the server looks up the session ID. Session state lives on the server (memory, Redis, DB).
// Login — server creates session, sets cookie
POST /login → server creates session { userId, expires }
Set-Cookie: sessionId=abc123; HttpOnly; Secure; SameSite=Strict
// Subsequent requests — browser sends cookie automatically
GET /profile
Cookie: sessionId=abc123 // server looks up session in Redis
Pro: instant revocation — delete the session record. Con: requires session store, doesn't scale horizontally without sticky sessions or shared Redis.
The server issues a signed token containing claims (userId, roles, expiry). The token is self-verifiable — no database lookup needed. It has three base64-encoded parts: header.payload.signature.
// JWT payload (decoded — NOT encrypted, just base64)
{
"sub": "user_123",
"email": "user@example.com",
"role": "admin",
"iat": 1700000000,
"exp": 1700003600 // expires in 1 hour
}
// Signed with a server secret — tampering invalidates the signature
Pro: stateless — works across microservices without a shared session store. Con: cannot revoke individual tokens before expiry without a blocklist (defeating the stateless benefit).
This is the most common interview question in this area:
localStorage.getItem('token').document.cookie won't show it). Protected from XSS. Must mitigate CSRF separately. This is the recommended storage for access tokens.// Secure token storage — set by server, httpOnly
Set-Cookie: access_token=<jwt>; HttpOnly; Secure; SameSite=Strict; Path=/
// Client code cannot access it
document.cookie // won't show access_token
localStorage // empty — token not stored here
Access tokens are short-lived (15 min). Refresh tokens are long-lived (7–30 days) and stored securely (httpOnly cookie). When the access token expires, the client uses the refresh token to get a new one.
// Token refresh flow
1. Access token expires (401 response)
2. Client sends refresh token to /auth/refresh
3. Server validates refresh token, issues new access + new refresh token
4. Old refresh token is invalidated (rotation — prevents token reuse attacks)
5. Client retries original request with new access token
Rotation means each refresh token is single-use. If a stolen token is used, the legitimate user's next refresh attempt fails, alerting the system to a potential breach.
OAuth 2.0 is an authorization framework — "Sign in with Google" delegates authentication to a trusted provider. The frontend uses the Authorization Code flow with PKCE (no client secret exposed in browser).
// PKCE Authorization Code Flow
1. Generate code_verifier (random string) + code_challenge (SHA256 hash)
2. Redirect to OAuth provider: /authorize?code_challenge=...&response_type=code
3. User authenticates at provider, redirected back with ?code=...
4. Exchange code + code_verifier for tokens at /token endpoint
// ^ code_verifier proves the same client that started the flow is completing it
SSO (Single Sign-On): one authentication session works across multiple apps. Implemented via shared cookies on the same domain, or via OAuth/SAML with a central identity provider (Auth0, Okta, Cognito).
JWT is more secure than sessions — JWT is stateless (convenient for scale) but cannot be revoked without a blocklist. A stolen JWT is valid until expiry. Session IDs can be invalidated instantly.
Storing tokens in localStorage is fine — localStorage is readable by any JavaScript, including injected XSS scripts. An httpOnly cookie prevents this attack vector entirely.
SameSite=Strict fully prevents CSRF — SameSite cookies aren't sent on cross-site requests, which does mitigate most CSRF. But Strict breaks OAuth redirects and legitimate cross-site navigation. Lax is usually the right balance.
OAuth is an authentication protocol — OAuth 2.0 is an *authorization* framework. OpenID Connect (OIDC) is the authentication layer built on top of OAuth 2.0.
GitHub: uses httpOnly session cookies for web authentication; separate API tokens for programmatic access — different token types for different threat models
Vercel dashboard: short-lived JWTs for API calls + refresh token rotation in httpOnly cookies — balance of statelessness and security
Google Sign-In: Authorization Code + PKCE flow; Google issues an ID token (OpenID Connect); your backend validates the signature using Google's public keys
Enterprise SSO (Okta, Azure AD): SAML or OIDC — user logs in once, identity provider issues assertions accepted by dozens of internal apps
What are the security differences between storing a JWT in localStorage vs an HttpOnly cookie?
What is refresh token rotation and why is it important?
What is OAuth 2.0 PKCE and when should you use it?
What is the difference between authentication and authorization?
What is SSO (Single Sign-On) and how is it implemented on the frontend?
How would you implement silent token refresh in a SPA?
Reading answers is not the same as knowing them. Practice saying them out loud with AI feedback — that's what builds real interview confidence.