OAuth 2.0 is "delegated authorization": let app A act on behalf of user U at service S, without giving A the user's password. OIDC layers identity on top: tell app A who user U is. Together they're how nearly every "Sign in with…" button works in 2026, and how nearly every API-to-API call between cloud services works.
OAuth has a reputation for being confusing because the spec accumulated flows over a decade and the names ("implicit," "password," "code") describe ten subtly different things. OAuth 2.1 (RFC drafted 2024) cleans up the deprecations. Use it.
If you're building "Sign in with Google" you need OIDC. If you're letting a third-party app post on behalf of a user, you need OAuth. Most SSO use cases are OIDC. Most "API access between services" cases are OAuth.
The same authorization server (Auth0, Okta, Keycloak, Cognito, Azure AD) handles both.
In 2026, Authorization Code with PKCE is the right answer for nearly every OAuth flow.
1. Client redirects user to authorization server with:
- client_id
- redirect_uri
- response_type=code
- scope=...
- state=<random>
- code_challenge=<SHA256 of random verifier>
- code_challenge_method=S256
2. User authenticates with auth server (and consents to scopes).
3. Auth server redirects back to redirect_uri with ?code=AUTH_CODE&state=...
4. Client backend posts to /token with:
- grant_type=authorization_code
- code=AUTH_CODE
- redirect_uri=...
- client_id, client_secret (if confidential client)
- code_verifier=<original random>
5. Auth server validates (especially that SHA256(verifier) == challenge), returns:
- access_token (used to call APIs)
- refresh_token (used to get new access tokens)
- id_token (OIDC; identity claim)
PKCE (Proof Key for Code Exchange) was introduced for mobile apps (where the client secret can't be kept secret) and has been promoted to a universal requirement in OAuth 2.1. Use it always, even for confidential clients with secrets.
If a tutorial tells you to use these, the tutorial is out of date. Use authorization code + PKCE.
client_secret from the auth server, use it on the token endpoint.client_secret; PKCE is the substitute.Both use authorization code + PKCE. The only difference is whether the token endpoint call carries client_secret.
Common confusion: people use the ID token as an access token. Don't. The ID token tells you who; the access token authorizes what.
Many auth servers issue access tokens as JWTs. The receiving API validates:
/.well-known/jwks.json, cached).iss matches the expected issuer.aud includes your API's identifier.exp is in the future.scope or scp includes the required permission.Use a library. Hand-rolled JWT validation is one of the most common security bugs in the wild. The classic flaws:
alg: none. Yes, the JWT spec allowed unsigned tokens. Reject any non-expected algorithm explicitly.kid from a trusted JWKS endpoint.Refresh tokens are powerful. A leaked refresh token gives an attacker continued access until you detect and revoke it.
Defences:
Scopes describe what an access token can do. Bad scope design:
/v1/users scope) — couples scope vocabulary to API surface.Better:
orders:read, orders:write, payments:read.Apps request the minimum scopes they need. Users see the consent screen; ask for the minimum.
ID tokens are JWTs with a defined claim set:
iss — the issuer.sub — the unique user ID at the issuer. Stable; the right thing to use as your internal user ID.aud — your client ID.exp, iat — expiry, issued at.email, name, picture — standard profile claims (only if you requested the corresponding scopes).nonce — replay protection; you generate it, the auth server echoes it.The userinfo endpoint returns the same claims (and possibly more) and is queryable with the access token. Useful for fresh data that might have changed since the ID token was issued.
email_verified=false. A user can claim any email; OIDC providers require explicit verification before email_verified=true. Check the flag before using email as identity.email as primary key. Emails change; users merge accounts at the IdP; don't key on email. Key on (iss, sub).POST /token/introspect). Use it for high-stakes operations; the cost is one extra round-trip.