# Auth: OAuth, JWT & Sessions > Delegate identity with OAuth, carry claims in JWTs, store state in sessions. Frontend architecture guidance from fearchitect, written by Abas Turabli and last reviewed 2026-06-21. Source: https://fearchitect.com/topics/auth-oauth-jwt-sessions Use it as reference for the task at hand. Before changing code, check this guidance against the codebase: where the code already makes a different, deliberate choice, flag the conflict instead of rewriting it. Library APIs move faster than this guide, so confirm exact signatures in the official docs linked at the end. ## Summary OAuth 2.0 / OIDC lets users grant your app access without sharing passwords. JWTs carry claims in a self-contained, signed token; sessions store state on the server. Each approach carries different trade-offs for revocation, storage, and XSS exposure. The BFF pattern resolves the SPA token-storage dilemma. ## OAuth 2.0 / OIDC OAuth 2.0 is an authorization framework that lets users grant a third-party app scoped access to their resources on another service — without exposing their credentials. OpenID Connect (OIDC) is a thin identity layer on top of OAuth 2.0 that adds a signed ID token with user claims (sub, email, name). The authorization-code flow with PKCE (Proof Key for Code Exchange) is the correct flow for SPAs and mobile apps. PKCE prevents auth-code interception attacks by binding the authorization request to a one-time code verifier that the client generates and the token endpoint validates. ## Diagram ```mermaid sequenceDiagram participant U as User participant SPA participant AS as Auth Server participant API U->>SPA: Click "Log in" SPA->>AS: /authorize + code_challenge (PKCE) AS->>U: Login / consent screen U->>AS: Credentials approved AS->>SPA: Redirect with auth_code SPA->>AS: /token + code_verifier AS->>SPA: access_token + id_token ``` Authorization-code + PKCE flow: the code_verifier ties the token exchange to the original request, blocking interception attacks. ## JWT vs server sessions | Dimension | JWT (stateless) | Server session (stateful) | | --- | --- | --- | | **State location** | Encoded in token, held by client | Session record on server (DB/Redis) | | **Revocation** | Not possible until expiry (need blocklist) | Immediate — delete the session record | | **Scalability** | No server lookup; scales horizontally | Session store becomes shared dependency | | **Token size** | Larger — carries all claims inline | Small ID; claims fetched server-side | | **Best for** | Stateless APIs, short-lived machine tokens | User sessions needing instant logout | ## Watch out: Cookies vs localStorage for token storage Store tokens in HttpOnly Secure SameSite=Strict cookies, not localStorage. localStorage is readable by any JavaScript on the page — a single XSS vulnerability drains every user token. HttpOnly cookies are invisible to JS; SameSite=Strict blocks CSRF. Short-lived access tokens (5–15 min) plus a refresh token in an HttpOnly cookie is the standard pattern. ## BFF token-handler pattern - A Backend for Frontend (BFF) handles the OAuth code exchange server-side, keeping tokens off the browser entirely. - The BFF sets HttpOnly cookies for the session; the SPA never sees raw access or refresh tokens. - Downstream API calls are made server-side by the BFF, which attaches the access token as a Bearer header. - Logout hits the BFF, which revokes the refresh token and clears the cookie atomically. - Auth0 and Okta publish reference BFF implementations; Next.js Auth.js uses this pattern by default. ## Key terms - **PKCE**: Proof Key for Code Exchange — one-time code verifier that binds an auth request to its token exchange, blocking interception. - **OIDC**: OpenID Connect — identity layer on OAuth 2.0 that issues a signed ID token containing user claims. - **JWT**: JSON Web Token — base64url-encoded header + payload + signature; stateless, self-contained, cannot be revoked before expiry. - **HttpOnly cookie**: Browser cookie inaccessible to JavaScript; protects tokens from XSS exfiltration. - **BFF (Backend for Frontend)**: Server layer that holds OAuth tokens and exposes a session cookie to the SPA, keeping tokens off the client. ## Related topics - [XSS, CSRF & Clickjacking](https://fearchitect.com/topics/xss-csrf-clickjacking.md): Three browser-level attacks and the headers that stop them. - [CSP & Trusted Types](https://fearchitect.com/topics/csp-trusted-types.md): Block script injection and DOM XSS at the browser's policy layer. - [Backend for Frontend (BFF)](https://fearchitect.com/topics/backend-for-frontend.md): A per-client server layer that shapes and aggregates APIs for one frontend. - [API Gateway (for Frontends)](https://fearchitect.com/topics/api-gateway.md): Single entry point that routes, authenticates, and rate-limits across services. - [Supply Chain Security](https://fearchitect.com/topics/supply-chain-security.md): Stop malicious npm packages and third-party scripts from owning your app. ## Further reading - [OAuth 2.0 Security Best Current Practice (RFC 9700)](https://datatracker.ietf.org/doc/html/rfc9700) - [PKCE specification (RFC 7636)](https://datatracker.ietf.org/doc/html/rfc7636) - [Auth.js (Next.js) docs](https://authjs.dev/) - [OWASP — Session Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html)