OAuth 2.0 and JWT: Authentication and Authorization Guide
OAuth 2.0 and JSON Web Tokens (JWT) form the backbone of modern API authentication and authorization. From social login buttons to machine-to-machine API communication, understanding these protocols is essential for any developer building web or mobile applications. The 2025 Okta State of Identity report shows that OAuth 2.0 is now used by 94% of enterprises, with JWT being the token format of choice for 87% of new implementations. This guide covers OAuth 2.0 authorization flows, JWT structure and validation, security best practices, and common implementation pitfalls.
OAuth 2.0 Authorization Framework
OAuth 2.0 (RFC 6749) is an authorization framework that enables third-party applications to obtain limited access to user accounts without exposing credentials.
Authorization Code Flow (with PKCE)
The Authorization Code flow is the recommended grant type for most applications. The client directs the user to the authorization server, the user authenticates and consents, the server returns an authorization code to the client via a redirect URI, and the client exchanges this code for tokens.
For native mobile apps and single-page applications, PKCE (Proof Key for Code Exchange, RFC 7636) prevents authorization code interception. The client generates a code_verifier (random 43-128 character string) and a code_challenge (SHA-256 hash of the verifier). The challenge is sent in the authorization request; the verifier is sent in the token exchange. Even if an attacker intercepts the authorization code, they cannot exchange it without the verifier.
Client Credentials Flow
Machine-to-machine communication uses the Client Credentials flow (RFC 6749 section 4.4). The client authenticates directly with the authorization server using its client ID and client secret (or a signed JWT assertion, RFC 7523) and receives an access token without user context. This flow must never be used in browser or mobile apps — the client secret cannot be stored securely in those environments.
Implicit Grant (Deprecated)
The Implicit grant (RFC 6749 section 4.2) returned the access token in the URL fragment. It was deprecated in OAuth 2.1 due to security weaknesses: tokens exposed in browser history, insufficient redirect URI validation, and lack of client authentication. Use Authorization Code + PKCE instead.
JWT Structure and Validation
JWTs (RFC 7519) are URL-safe, self-contained tokens consisting of three Base64URL-encoded parts separated by dots: header, payload, and signature.
Header
The header typically contains the token type ("typ": "JWT") and the signing algorithm ("alg": "RS256"). Critical security consideration: the alg header parameter must be strictly validated. The famous “none” algorithm attack occurs when servers accept a JWT with "alg": "none" (no signature), allowing arbitrary token forging. Libraries must be configured to reject the none algorithm in all production environments.
Payload (Claims)
The payload contains claims about the entity and additional metadata. Standard claims (registered claim names) include: iss (issuer), sub (subject), aud (audience), exp (expiration time), nbf (not before), iat (issued at), and jti (JWT ID). The aud claim is frequently misvalidated — servers must verify that the token’s audience matches their own identifier. A token issued for service A should not be accepted by service B.
Signature Verification
The signature is computed over the header and payload. For RS256 (RSA with SHA-256), the server verifies using the issuer’s public key. For HS256 (HMAC with SHA-256), the server and issuer share a symmetric secret. HS256 introduces a critical risk: if the verification library passes the secret to the HMAC function and the alg header says “HS256” but the token was originally RS256-signed, the attacker can use the public key (which is public knowledge) as the “secret” for HMAC verification. This algorithm confusion attack (detailed in CVE-2015-9235) requires libraries to reject tokens when the asymmetric public key has been used as an HMAC secret.
Key Rotation
Authorization servers should rotate signing keys periodically. The JWKS (JSON Web Key Set) endpoint publishes current public keys with unique kid (key ID) values. Clients cache keys and use the kid in the JWT header to select the correct key for verification. Implementations should re-fetch JWKS on cache miss to handle rotation gracefully.
Token Management
Access Token Lifetime
Short-lived access tokens limit the window of compromise. Standard lifetimes range from 15 minutes to 1 hour depending on risk profile. Very short lifetimes (5-10 minutes) are appropriate for high-value APIs. The token should include the exp (expiration) claim, and servers must validate exp on every request.
Refresh Token Rotation
Refresh tokens (long-lived, used to obtain new access tokens) introduce greater risk. OAuth 2.0 best practices recommend refresh token rotation: each refresh request returns a new access token AND a new refresh token, invalidating the previous one. This limits the window for stolen refresh tokens. If a compromised refresh token is submitted after the rotated token has been used, the authorization server can detect the breach, revoke all tokens for that session, and alert the user.
Token Revocation
RFC 7009 defines the token revocation endpoint. Revocation must be supported for both access tokens and refresh tokens. When a user changes their password, logs out, or an administrator suspends an account, associated tokens must be revoked. Stateless JWT revocation requires a blocklist (sorted set in Redis, database table) checked on every request, or very short-lived tokens with refresh token enforcement.
Security Best Practices
Redirect URI Validation
Strict redirect URI validation prevents authorization code interception. The OAuth 2.0 Security BCP (RFC 9700) and OAuth 2.1 require exact match comparison of redirect URIs — prefix matching is insufficient and leads to open redirector vulnerabilities. A redirect URI of https://example.com/callback must not match https://example.com/callback_evil.
CSRF Protection
The state parameter (a cryptographically random value) must be sent in the authorization request and validated in the callback. This prevents CSRF attacks where an attacker starts an OAuth flow and the victim completes it, linking the attacker’s account to the victim’s session in the client application. The state value must be bound to the user’s session (e.g., a hash of the session ID plus a random nonce).
Token Binding
Token binding (RFC 8471) cryptographically binds tokens to the TLS connection, preventing token export and replay. While not widely deployed due to browser support limitations, it provides the strongest security for bearer tokens. DPoP (Demonstration of Proof-of-Possession, RFC 9449) is a practical alternative that binds tokens to a client-held public key via signed header values.
OAuth 2.1 and Emerging Standards
OAuth 2.1, published as RFC in 2024, consolidates security best practices developed over the past decade into a single specification. Key changes include: the Implicit grant is removed entirely — Authorization Code with PKCE replaces it for all public clients; the Resource Owner Password Credentials grant is eliminated; client credentials flow requires client authentication (public clients cannot use it); refresh token rotation is recommended as standard practice; redirect URI must use exact match comparison; and the state parameter is mandatory, not optional.
Token Exchange for Microservices
Token Exchange (RFC 8693) enables delegation across service boundaries. An API gateway authenticates once and exchanges its token for a downstream-specific token with narrower scope. This prevents the “token too powerful” anti-pattern where a gateway token carries all permissions. Token Exchange requires: sender authentication (client credentials or JWT assertion), target resource specification, and scope constraints. The authorization server validates the original token and issues a new one with potentially different claims, audience, and expiration. Grant Management (RFC 9471) extends this by providing a standardized protocol for listing, updating, and revoking individual grants — enabling user-facing application consent dashboards that work across OAuth implementations. Mutual TLS (mTLS) for OAuth 2.0 (RFC 8705) provides an alternative client authentication method that binds tokens to client certificates, preventing token replay in microservice architectures.
FAQ
What is the difference between OAuth 2.0 and OpenID Connect? OAuth 2.0 is an authorization framework (delegates access). OIDC is an authentication layer on top of OAuth 2.0 (verifies identity). OIDC adds the ID token (a JWT containing identity claims) and the UserInfo endpoint.
Should I use JWT for session management? JWT-based sessions avoid database lookups for each request but cannot be revoked server-side without a blocklist. For most web applications, opaque session identifiers stored in server-side storage are more secure and no slower with proper caching.
What is the best JWT signing algorithm? RS256 (RSA 2048-bit) or ES256 (ECDSA P-256). Avoid HS256 — it requires symmetric key distribution to each verifier, multiplying attack surface.
How do I handle JWT expiry in a mobile app? Use refresh tokens with rotation. The app stores the refresh token in the Keychain (iOS) or Keystore (Android) and transparently refreshes the access token when it expires.
What happens if my JWKS server is down? Clients cache JWKS responses (typically 1 hour). In case of cache miss, retry with exponential backoff. Design for availability: serve JWKS from a CDN, and rotate keys at least 24 hours before removing old keys from the JWKS endpoint.
For foundational security principles, see our Security Guide. Learn about identity management at scale with IAM Guide. For mobile-specific token handling, read Mobile Security Guide.