Every API needs to answer: who is this user, and what are they allowed to do? Roll your own auth and you'll have a CVE within months. OAuth 2.0 is how you delegate authentication to a trusted identity provider. JWTs are how you carry proof of identity between services.
Understand both, including when NOT to use JWTs as sessions (a surprisingly common mistake).
02
Authentication vs authorization
Authentication (authn) — "who are you?" Verifies identity. Username + password, social login, MFA.
Authorization (authz) — "what can you do?" Checks permissions. RBAC (role-based), ABAC (attribute-based), resource-level policies.
OAuth 2.0 is an authorization protocol, not an authentication protocol. OpenID Connect (OIDC) sits on top of OAuth to add authentication. When people say "OAuth login," they usually mean OIDC + OAuth together.
03
OAuth 2.0 authorization code flow
The modern canonical flow for web apps (with PKCE extension for public clients):
User clicks "Log in with Google."
App redirects browser to Google's authorization endpoint with client_id + requested scopes + redirect URI + PKCE challenge.
User authenticates with Google, consents to scopes.
Google redirects browser back to your app with an authorization code.
Your backend exchanges the code + PKCE verifier for an access token (short-lived) and a refresh token (long-lived).
Your backend uses the access token to call Google APIs, or creates its own session for the user.
Key insight: the access token never touches the browser. Client-side Single-Page Apps use PKCE to prevent code interception; public clients get the code via redirect but also need the PKCE verifier (secret only the client knows) to exchange it.
04
JWT anatomy
JSON Web Token — three base64 parts joined by dots: header.payload.signature.
HEADER {"alg":"RS256","typ":"JWT"}
PAYLOAD {"sub":"42","iss":"https://auth.example.com","exp":1735689600,"roles":["admin"]}
SIGNATURE RS256-signature over header + payload
Server verifies by recomputing the signature with its public key. Tampered payload → signature mismatch → reject. The payload (claims) is not encrypted — it's base64, readable by anyone. Don't put secrets in there.
Standard claims: sub (subject/user), iss (issuer), exp (expiry), aud (audience), iat (issued at). Custom claims (roles, tenant_id) are added by the issuer.
05
Stateless JWTs vs sessions in Redis
JWT-based auth
Stateless, no session store
Every request carries the JWT. Server verifies signature + expiry. No DB or Redis lookup. Catch: revoking access before expiry is hard. If a user's JWT is stolen, they keep access until it expires (usually 15 min to 1 hour).
Opaque session tokens
Random string, state in Redis
Token is an opaque ID; server looks up sessions:abc123 in Redis. Easy to revoke — just DELETE the key. Adds a Redis round-trip per request but Redis is fast. Industry default for user sessions.
Common mistake
Using JWTs as user sessions because "stateless is cool." Then trying to add revocation, which requires the very session store you tried to avoid. Moral: use JWTs for service-to-service auth and short-lived access tokens; use opaque tokens for long-lived user sessions.
06
Deep dive — refresh tokens done right
Access tokens are short (15 min). Refresh tokens are long (days/weeks/months) and used to mint new access tokens without re-asking the user.
Threats:
Refresh token theft. Attacker steals the refresh token, gets new access tokens indefinitely. Mitigation: refresh token rotation — every use of a refresh token returns a new one and invalidates the old. If the attacker uses it, the real user's next refresh fails and you detect the compromise.
Token binding. Bind tokens to device fingerprints or TLS certificates. Stolen token from another device = rejected.
Reuse detection. If an old (already-rotated) refresh token is used, invalidate the whole family — both the attacker and the real user are logged out. Safer to re-auth than to keep serving the attacker.
Auth0, Okta, and every modern IdP do all three by default. If you're rolling your own, follow OAuth 2.1 draft recommendations — they codify what's actually safe.