OAuth 2.0 & OpenID Connect
Authentication: OAuth 2.0 & OpenID Connect OAuth 2.0 is an authorization framework — it lets users grant third-party apps access to their resources without shar…
Authentication: OAuth 2.0 & OpenID Connect
OAuth 2.0 is an authorization framework — it lets users grant third-party apps access to their resources without sharing credentials. OpenID Connect (OIDC) is a thin identity layer on top of OAuth 2.0 that adds authentication.
OAuth 2.0 Roles
Resource Owner — the user who owns the data
Client — the application requesting access (your app)
Authorization Server — issues tokens (Google, GitHub, Auth0, your own)
Resource Server — the API being accessed (Google APIs, GitHub API)
Grant Types (Flows)
Authorization Code + PKCE — for user-facing web/mobile apps (RECOMMENDED)
1. App redirects user to Authorization Server with code_challenge (PKCE)
2. User authenticates and grants consent
3. AS redirects back with authorization_code
4. App exchanges code + code_verifier for access_token + refresh_token
5. App uses access_token to call Resource Server APIs
PKCE (Proof Key for Code Exchange): prevents auth code interception attacks.
Required for public clients (SPAs, mobile apps). Use for all new flows.
Client Credentials — for machine-to-machine (no user involved)
1. Service POSTs client_id + client_secret to AS
2. AS returns access_token (no refresh token)
3. Service uses access_token to call other services
Device Flow — for CLIs, smart TVs (no browser)
1. App requests device_code and shows user_code to user
2. User visits URL and enters user_code on another device
3. App polls for token until user approves
Implicit flow: DEPRECATED — use Authorization Code + PKCE instead
Resource Owner Password: DEPRECATED — share credentials directly (legacy only)Authorization Code + PKCE Flow
// 1. Generate PKCE code verifier and challenge
const codeVerifier = base64urlEncode(crypto.randomBytes(32))
const codeChallenge = base64urlEncode(sha256(codeVerifier))
// 2. Redirect to Authorization Server
const authUrl = new URL('https://auth.example.com/oauth/authorize')
authUrl.searchParams.set('response_type', 'code')
authUrl.searchParams.set('client_id', 'my-client-id')
authUrl.searchParams.set('redirect_uri', 'https://app.example.com/callback')
authUrl.searchParams.set('scope', 'openid email profile')
authUrl.searchParams.set('state', randomState) // CSRF protection
authUrl.searchParams.set('code_challenge', codeChallenge)
authUrl.searchParams.set('code_challenge_method', 'S256')
window.location.href = authUrl.toString()
// 3. Handle callback (app receives code)
const code = new URLSearchParams(window.location.search).get('code')
// verify state matches
// 4. Exchange code for tokens
const response = await fetch('https://auth.example.com/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
code,
redirect_uri: 'https://app.example.com/callback',
client_id: 'my-client-id',
code_verifier: codeVerifier,
}),
})OpenID Connect (OIDC)
OIDC adds authentication on top of OAuth 2.0:
- ID Token (JWT) — contains user identity claims (sub, email, name, picture)
- UserInfo endpoint — GET /userinfo with access_token to get user profile
- Discovery document — /.well-known/openid-configuration (auto-discovery)
OIDC Scopes:
openid — required for OIDC; returns ID token with sub claim
email — adds email + email_verified claims
profile — adds name, picture, given_name, family_name, locale
address — postal address
phone — phone number
ID Token validation (must do on client/server):
1. Verify signature using AS public keys (from JWKS endpoint)
2. Verify iss = expected issuer
3. Verify aud = your client_id
4. Verify exp > now (not expired)
5. Verify iat is reasonable (not too old)
6. Verify nonce if included in auth request
Popular OIDC providers:
Auth0, Okta, AWS Cognito, Keycloak (self-hosted), Google, GitHub (partial OIDC)