# Frontend Authentication: Cookies, Tokens, and Session Management

Source: https://www.techinterview.org/post/3233475085/frontend-authentication-cookies-tokens-sessions/
Updated: 2026-06-30 · techinterview.org

Authentication is one of the most error-prone parts of a frontend application. Get it wrong and you have account takeover, session hijacking, or worse. Senior frontend interviews probe whether you understand the modern patterns: cookies vs tokens, OAuth flows, refresh strategies, and the security implications of each choice.

## The two main patterns

### Session cookies

Server creates a session, stores in DB. Client gets a session ID in a cookie. Server validates the cookie on every request.

Pros:

- HttpOnly cookies are not readable from JS — XSS-safe for the token

- Centralized session control on server

- Easy logout (server invalidates session)

Cons:

- Requires same-origin or careful CORS setup

- Stateful server (database lookup per request) — though usually cached

### JWT tokens

Server signs a JWT with claims about the user. Client sends it in Authorization header.

Pros:

- Stateless — no server-side session lookup

- Works across domains and microservices

- Standards-based

Cons:

- Cannot easily revoke (until expiry)

- Token storage on client is a security headache

- Larger payload than session cookies

## Where to store tokens

This is the most-debated topic. The options:

- **localStorage:** JS-readable. XSS can steal tokens. Wrong choice.

- **sessionStorage:** same XSS risk; cleared on tab close.

- **HttpOnly cookies:** not JS-readable. XSS cannot steal directly. Best for tokens.

- **In-memory:** JS variable. Safe from XSS but lost on reload — paired with refresh tokens.

## The refresh token pattern

Modern recommended pattern:

- Short-lived access token (5–15 minutes), in memory

- Long-lived refresh token (1–30 days) in HttpOnly Secure SameSite=Strict cookie

- Access token expires → use refresh token to get new access token

- Refresh token compromised → server can revoke

This bounds the damage of token theft and gives the server centralized control.

## OAuth and OpenID Connect

For "Sign in with Google/Apple/GitHub" flows:

- Frontend redirects user to provider with client_id

- User authenticates with provider

- Provider redirects back with authorization code

- Frontend sends code to backend

- Backend exchanges code for access + ID tokens directly with provider

- Backend validates ID token, creates own session for the user

Critical: never expose client_secret in frontend. Token exchange must happen server-side.

## PKCE (Proof Key for Code Exchange)

Modern OAuth flows use PKCE to prevent authorization code interception. The flow:

- Frontend generates a random code_verifier; hashes to code_challenge

- Sends code_challenge with the auth request

- Provider returns code; frontend sends code + code_verifier

- Provider validates: code_verifier hashed must equal code_challenge

Used in SPAs and mobile apps. Most OAuth libraries handle PKCE automatically.

## Handling auth state in React

Common pattern:

- useAuth() hook exposes current user and login/logout

- Provider at app root subscribes to auth state changes

- ProtectedRoute redirects unauthenticated users

- useEffect on app mount checks for existing session (e.g., calls /me endpoint)

## Logout

For session cookies: hit a logout endpoint; server clears the session and Set-Cookie expires the cookie.

For JWTs: clear in-memory token and refresh token. Optionally call a revocation endpoint to invalidate the refresh token server-side.

Multi-device: server-side revocation lists allow logout-from-all-devices.

## Multi-factor authentication

Common UX:

- User enters username + password

- Server returns "MFA required" with a temporary token

- User enters TOTP code or approves push

- Server validates; returns access token

WebAuthn (passkeys) is becoming standard. Modern auth allows skipping passwords entirely with passkey + device verification.

## Common mistakes

- Storing JWTs in localStorage

- Logging tokens (in error reports, console)

- Sending tokens via URL query parameters (logged in server access logs)

- Not using HTTPS (cleartext credentials)

- Not validating tokens server-side (trust)

- Long-lived access tokens (no compromise window mitigation)

## Frequently Asked Questions

### Should I roll my own auth or use a service?

Use a service. Auth0, Clerk, Supabase Auth, AWS Cognito, Firebase Auth — all are battle-tested. Rolling your own is risky; subtle bugs are catastrophic.

### Should I use sessions or JWTs?

For monolithic web apps: sessions (HttpOnly cookies). For multi-service or mobile apps: JWTs with refresh tokens. Both are valid; sessions are simpler.

### What about passkeys?

WebAuthn / passkeys are the future. They eliminate passwords. Adoption is growing — Apple, Google, Microsoft all support. Add as an option alongside passwords for now.
