Tags: oauth2, oidc, security, authentication, authorization, jwt, sso, identity
Level: intermediate
TL;DR: OAuth 2.0 is an authorization framework for delegated access. OpenID Connect (OIDC) is an identity layer built on top of OAuth 2.0 to provide authentication and user profile information via ID tokens.
OAuth 2.0 handles authorization (delegated access), not authentication.
OIDC handles authentication (verifying user identity) and provides an ID Token (usually a JWT).
Access Token: Used by the client to access a resource server on behalf of the user.
ID Token: JWT containing user identity claims (sub, iss, aud, exp, iat).
Refresh Token: Long-lived token used to obtain new access tokens without prompting the user.
Authorization Code Flow: Most secure flow for confidential and public clients (with PKCE).
PKCE (Proof Key for Code Exchange): Prevents authorization code interception attacks, mandatory for SPAs and mobile apps.
Implicit Flow: Deprecated, previously used for SPAs, returns tokens directly in the URL fragment.
Client Credentials Flow: Used for machine-to-machine (M2M) communication without a user context.
Scopes: Define the permissions requested by the client (e.g., openid, profile, email).
Q: What is the difference between OAuth 2.0 and OIDC?R: OAuth 2.0 is purely for authorization (granting access to resources). OIDC adds an identity layer on top to handle authentication, giving me an ID token with user details.
Q: Why should we use PKCE with the Authorization Code flow?R: PKCE protects against authorization code interception. I generate a code_verifier and send its hash (code_challenge) during the authorization request, then send the verifier when exchanging the code for tokens.
Q: Can I use an Access Token to authenticate a user?R: No, access tokens are meant for resource servers. To authenticate a user in my client application, I must use the ID Token provided by OIDC.
Q: How do you handle token expiration in a frontend app?R: I keep the short-lived access token in memory and use a refresh token stored securely (e.g., HTTP-only cookie) to request a new access token when it expires.
Using the Implicit flow instead of Authorization Code with PKCE for SPAs.
Decoding the Access Token on the client side to authenticate the user (Access Tokens are opaque to the client, use the ID Token instead).
Storing tokens in localStorage, making them vulnerable to XSS attacks (prefer HTTP-only, secure cookies).
Failing to validate the ID token signature, issuer (iss), and audience (aud) on the backend.
Passing sensitive information in the URL or as plain text claims without encryption.
// Generate PKCE code_verifier and code_challenge
const generateRandomString = (length) => {
const array = new Uint32Array(length / 2);
crypto.getRandomValues(array);
return Array.from(array, dec => ('0' + dec.toString(16)).substr(-2)).join('');
};
const generateCodeChallenge = async (codeVerifier) => {
const encoder = new TextEncoder();
const data = encoder.encode(codeVerifier);
const digest = await crypto.subtle.digest('SHA-256', data);
return btoa(String.fromCharCode(...new Uint8Array(digest)))
.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
};
const code_verifier = generateRandomString(128);
const code_challenge = await generateCodeChallenge(code_verifier);
[ ] OIDC discovery endpoint (/.well-known/openid-configuration)
[ ] Validating JWT signatures using JWKS (JSON Web Key Set)
[ ] Differences between back-channel and front-channel logout
OAuth 2.0 RFC 6749
OpenID Connect Core 1.0 Specification
OAuth 2.0 for Browser-Based Apps (BCP)