JWT vs OAuth2 vs OpenID Connect: Simple Explanation for Developers
TL;DR
- JWT (JSON Web Token) is a token format — a compact, URL-safe way to represent claims that can be signed (and optionally encrypted).
- OAuth 2.0 is an authorization framework for delegated access (how a client gets permission to access a resource).
- OpenID Connect (OIDC) is an identity layer built on top of OAuth 2.0 that enables authentication (verifying who a user is) and returns an ID Token (usually a JWT).
- They are complementary: OAuth2 handles authorization, OIDC adds authentication and ID tokens, and JWT is one common token representation used by both.
This article gives a developer-friendly, in-depth view: history, concepts, flows, security best practices, practical examples and when to use each.
Contents
- Background & history (standards)
- Core concepts & actors
- JWT deep dive (structure, signing, validation)
- OAuth 2.0 deep dive (flows, endpoints, tokens)
- OpenID Connect deep dive (ID token, discovery, userinfo)
- Comparing JWT, OAuth2, OIDC (short decision guide)
- Common flows and practical examples (code snippets)
- Security pitfalls & best practices
- Deployment/architecture patterns (JWT vs opaque tokens, introspection, gateways)
- Popular libraries and providers
- Current state & future directions
- FAQs and quick recommendations
Background & history (standards)
- JWT: defined in RFC 7519 (2015). Part of a family of JSON-based identity specs (JWS, JWE, JWK).
- OAuth 2.0: defined in RFC 6749 (2012). A widely used framework for delegated authorization.
- OpenID Connect: published 2014 (built on OAuth2). Core spec adds authentication semantics and ID Tokens.
Why confusion? Because these technologies often appear together (e.g., an OAuth2 server emits JWT access tokens and OIDC emits JWT ID tokens). But they answer different questions:
- Who is the user? (authentication) — OIDC
- Can this client do X on behalf of the user? (authorization) — OAuth2
- How do we encode claims or tokens? (token format) — JWT
Core concepts & actors
Common actors (OAuth2/OIDC terminology):
- Resource Owner: the user or entity owning the resource.
- Client: application wanting access (web app, mobile app, backend).
- Authorization Server: issues tokens and performs authentication/consent.
- Resource Server (API): consumes and validates access tokens to permit access.
Key terms:
- Access token: used to access protected resources (opaque or JWT).
- Refresh token: used to obtain new access tokens without re-authenticating the user.
- ID token (OIDC): token containing user identity claims (usually a JWT).
- Scope: requested/allowed permissions (e.g., profile email read).
- Grant/Flow: method a client uses to obtain tokens (authorization code, client credentials, etc.).
- JWK: JSON Web Key; public key format used to expose verification keys.
JWT deep dive
What is a JWT?
- Compact, URL-safe token composed of 3 parts: header, payload (claims), signature.
- Encoded as Base64URL(header) + "." + Base64URL(payload) + "." + Base64URL(signature).
Header example: `` { "alg": "RS256", "typ": "JWT", "kid": "abc123" } ``
Payload (claims) example: `` { "iss": "https://auth.example.com", "sub": "user-123", "aud": "api.example.com", "exp": 1618887999, "iat": 1618884399, "scope": "read:messages" } ``
Standard claims:
- iss (issuer), sub (subject), aud (audience), exp (expiration), nbf (not before), iat (issued at), jti (unique id).
Signing and encryption:
- JWS (signed): common algorithms HS256 (HMAC) and RS256/ES256 (asymmetric). RS/ES recommended for distributed verification (no shared secret).
- JWE (encrypted): JWT can be encrypted to hide claims.
Advantages
- Self-contained: resource servers can validate without contacting the auth server (if they have verification keys).
- Compact and widely supported.
Disadvantages and caveats
- Revocation is hard for long-lived JWTs (stateless). Use short TTLs and/or revocation strategies (blacklists or introspection).
- Large JWTs increase request size (cookies/headers).
- Inappropriate audience/issuer checks are common bugs.
Example: create & verify JWT (Node.js) ```js // npm install jsonwebtoken jwks-rsa const jwt = require('jsonwebtoken'); const fs = require('fs');
// Signing with RSA private key (server) const privateKey = fs.readFileSync('./private.pem'); const token = jwt.sign({ sub: 'user-123', scope: 'read' }, privateKey, { algorithm: 'RS256', expiresIn: '1h', issuer: 'https://auth.example.com', audience: 'https://api.example.com' }); console.log(token);
// Verification (resource server) const publicKey = fs.readFileSync('./public.pem'); try { const payload = jwt.verify(token, publicKey, { algorithms: ['RS256'], issuer: 'https://auth.example.com', audience: 'https://api.example.com' }); console.log(payload); } catch (err) { console.error('Invalid token', err); } ```
OAuth 2.0 deep dive
Purpose: delegated authorization — let a third-party client access resources on behalf of the user.
Primary endpoints:
- Authorization endpoint: user-agent redirect for user consent and auth.
- Token endpoint: exchange authorization code (or credentials) for tokens.
- (Optional) Revocation and introspection endpoints.
Main grant types (flows)
- Authorization Code (with PKCE): recommended for web & mobile apps. Server-side or public clients get a code then exchange it for tokens.
- Implicit: older pattern for single-page apps returning tokens directly; largely deprecated due to security concerns.
- Client Credentials: machine-to-machine; client acts on its own behalf (no user).
- Resource Owner Password Credentials: deprecated/avoid — app collects user credentials directly.
- Device Authorization (device code): for input-constrained devices.
- Refresh Token: refresh access tokens without re-prompting the user.
Important: PKCE (Proof Key for Code Exchange)
- Protects authorization code flow for public clients (mobile, SPAs) from code interception.
- Client generates codeverifier and codechallenge sent to auth endpoint; token exchange requires the code_verifier.
Token types:
- Access tokens: may be JWT or opaque strings — used at resource servers.
- Refresh tokens: usually opaque and long-lived; used to get new access tokens.
Sequence: Authorization Code flow (simplified)
- Client redirects user to Authorization Endpoint with clientid, redirecturi, scope, state, code_challenge.
- User authenticates and consents.
- Auth server redirects back with code and state.
- Client sends code + code_verifier to Token Endpoint.
- Server returns accesstoken (and maybe refreshtoken).
Curl example: exchange code for tokens (sketch) ``bash curl -X POST https://auth.example.com/oauth/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "granttype=authorizationcode&code=AUTHCODE&redirecturi=https://app.example.com/cb&clientid=CLIENTID&codeverifier=CODEVERIFIER" ``
OpenID Connect deep dive
What OIDC adds:
- ID Token: JWT that contains identity claims about the authenticated user (sub, iss, aud, exp, iat, nonce...). It's intended for the client (Relying Party).
- Well-Known Discovery: /.well-known/openid-configuration gives endpoints, supported features, JWK URI.
- UserInfo Endpoint: returns additional claims about the user (profile, email) using the access_token.
- Standard scopes: openid (required to do OIDC), profile, email, address, phone, offline_access (request refresh token).
- Nonce: used to mitigate replay attacks against the ID token — client sends nonce during authorization request and validates it matches ID token claim.
Typical OIDC flow:
- Same as OAuth2 Authorization Code flow, but include scope=openid (and optionally profile,email).
- Token response includes idtoken (JWT) + accesstoken.
- Client validates id_token (signature, issuer, audience, exp, nonce).
ID token example payload: `` { "iss": "https://auth.example.com", "sub": "user-123", "aud": "client-abc", "exp": 1618887999, "iat": 1618884399, "nonce": "n-0S6WzA2Mj", "email": "[email protected]", "emailverified": true } ``
Discovery example (curl) ```bash curl https://auth.example.com/.well-known/openid-configuration
returns JSON with issuer, authorizationendpoint, tokenendpoint, jwksuri, userinfoendpoint...
```
Key OIDC validations:
- Validate signature (using JWKs from jwks_uri).
- Validate iss, aud, exp, iat.
- Verify nonce (for code flow with id_token).
- If access token is used at userinfo endpoint, it must be sent securely.
Comparing JWT vs OAuth2 vs OIDC — short decision guide
- Need to ...