Sessions, JWTs, and OAuth/OIDC: Three Different Jobs
You log out and the admin panel still accepts the old token. Or you build "Sign in with Google" and accidentally treat an access token as proof of identity. Auth failures feel like product bugs until you realize you mixed three different models.
This article is the credential-model comparison: server sessions, JWTs, and OAuth 2.0 (with OIDC when you need identity). For how to validate JWT claims safely, see JWT deep dive. For Basic / Bearer / API key wire formats on REST, see REST authentication methods. For object-level authorization after login, see API security practices.
Skimmer: which model fits?
Sessions store state on the server and send a session ID cookie — instant revoke, natural for server-rendered apps. JWTs carry signed claims the client presents on each request — scalable across services, harder to revoke before expiry. OAuth 2.0 delegates authorization to an authorization server; OIDC adds identity (ID token) on top.
Decision order: classic web app that must kill sessions immediately → session cookie. Your APIs validate tokens across many instances without a shared session store → JWT (short-lived + refresh). Users grant a third party access or "Sign in with …" → OAuth 2.0 (+ OIDC for login). Production apps often combine them.
Quick reference
- Session — server state; httpOnly cookie; instant logout.
- JWT — signed claims; Bearer header or cookie; plan expiry + refresh.
- OAuth — delegated access; Authorization Code + PKCE for public clients.
- OIDC — identity layer on OAuth; validate iss, aud, exp on ID tokens.
- Never put secrets in JWT payloads — Base64 is not encryption.
Remember this
Sessions need server-side state to revoke instantly; self-contained tokens trade that away for statelessness; OAuth/OIDC exists to delegate trust to a third party — pick by which trade-off you can live with.
JWT (JSON Web Token)
A JWT is three Base64URL parts: header (algorithm), payload (claims like sub and role), and signature (HMAC or RSA). After login the server signs a token; later requests send Authorization: Bearer <token>. Any service with the verification key can validate without a session lookup — useful for stateless APIs and microservices.
Revocation is the hard part. A JWT stays valid until exp unless you add a denylist or rotate keys aggressively. Prefer short-lived access tokens (minutes) plus refresh tokens. Payload is readable to anyone who has the token — treat claims as public. Full validation steps live in the JWT deep dive.
Quick reference
- Best for: SPAs, mobile apps, microservices, API-to-API with shared verification.
- Strengths: no shared session store; works across domains/services.
- Weaknesses: hard to revoke early; token size grows with claims; XSS if stored in localStorage.
- Prefer httpOnly Secure cookies for browser storage when same-site fits.
- Sign with RS256/ES256 when many services verify; keep private keys only on the issuer.
Remember this
JWTs fit distributed APIs — keep payloads minimal and plan expiry, refresh, and verification.
Session-Based Auth
Session auth stores user state server-side — memory, Redis, or a database. On login the server creates a session and sets an httpOnly, Secure, SameSite cookie with the session ID. Each request sends the cookie; the server loads the session and user. Logout deletes the session — instant revocation.
This model fits traditional server-rendered apps and admin UIs. At scale you need a shared store (typically Redis) or sticky sessions. For a single-region web app with moderate traffic, sessions are often simpler than JWTs because the server owns all state.
Quick reference
- Best for: server-rendered apps, dashboards, instant logout requirements.
- Strengths: revoke by deleting server state; cookie is just an opaque ID.
- Weaknesses: shared session store or stickiness; awkward for pure native clients.
- Rotate session IDs after login to prevent fixation.
- Use Redis (or equivalent) in production — not only in-process memory.
Remember this
Sessions are the secure default when the server can own state and instant revoke matters.
OAuth 2.0
OAuth 2.0 solves delegated authorization: a user grants a third-party app limited access without sharing their password. "Sign in with Google" redirects to the provider; after consent the app exchanges an authorization code for tokens. OAuth alone is not authentication — OpenID Connect (OIDC) adds an ID token that asserts who the user is.
Do not implement the full protocol from scratch; use a maintained library or IdP (Auth0, Keycloak, Cognito, NextAuth, and similar). For SPAs and mobile, use Authorization Code with PKCE — Implicit flow is obsolete. Store refresh tokens server-side when possible.
Quick reference
- Best for: social login, third-party API access, enterprise SSO (OIDC/SAML).
- Strengths: no password storage for social login; scoped delegated access.
- Weaknesses: redirect complexity; provider dependency; easy to misconfigure.
- Always Authorization Code + PKCE for public clients.
- Validate ID tokens when OIDC is your authentication path.
Remember this
Use OAuth for delegated access and OIDC for "Sign in with …" — not as a substitute for understanding sessions vs JWTs.
Key takeaway
Production apps combine models: OIDC for social login, short-lived JWTs for your APIs, refresh tokens held server-side; or sessions for a classic web app with optional OAuth for social login. Choose by client type, revoke needs, and who issues identity — not by which acronym is trendy.
Practice (25 min): For one product surface, write which model owns login, which credential hits your API, and how logout works. Then implement one happy path and one 401 body for either a session cookie check or a Bearer JWT check.
Related Articles
Explore this topic