OAuth 2.0 and OpenID Connect Explained
OAuth 2.0 is an authorization framework that lets an application access resources on a user's behalf without handling the user's password. OpenID Connect (OIDC) is a thin identity layer built on top of OAuth 2.0 that adds authentication, allowing an application to verify who the user is. Together they power delegated access and single sign-on across much of the web, and using them correctly is essential to avoiding account-takeover vulnerabilities.
Authorization Versus Authentication
The distinction is fundamental. Authorization answers what an application is allowed to do, such as read a user's calendar. Authentication answers who the user is. OAuth 2.0 was designed for authorization, and using raw OAuth for login is error-prone. OIDC fills that gap by defining an ID token and a standard way to confirm identity, so applications should rely on OIDC rather than improvising authentication from access tokens. Conflating the two is a frequent design error: an access token proves the bearer may call an API, not that a specific human is present, so treating a valid access token as proof of login can let one user's token establish a session as someone else.
The Roles in an OAuth Flow
- Resource owner: the user who owns the data.
- Client: the application requesting access.
- Authorization server: the system that authenticates the user and issues tokens.
- Resource server: the API that holds protected resources and accepts access tokens.
Tokens
- Access token: a credential the client presents to the resource server. It is typically short-lived and often a JWT, though it can be an opaque string.
- Refresh token: a longer-lived credential used to obtain new access tokens without re-prompting the user. It must be stored securely and can be revoked.
- ID token: an OIDC JWT that describes the authenticated user, including claims such as subject and issuer, and is meant for the client, not the resource server.
How the Authorization Code Flow Works
The authorization code flow is the recommended flow for most applications. It keeps tokens out of the browser's address bar and out of untrusted contexts.
- The client redirects the user to the authorization server, including its client identifier, requested scopes, a redirect URI, and a random
statevalue. - The user authenticates and consents to the requested access.
- The authorization server redirects back to the client with a short-lived authorization code.
- The client exchanges the code, over a back-channel request, for an access token and optionally a refresh token and ID token.
GET /authorize?response_type=code
&client_id=app123
&redirect_uri=https://app.example.com/callback
&scope=openid%20profile
&state=xyz987
&code_challenge=hashed-verifier&code_challenge_method=S256
PKCE
Proof Key for Code Exchange (PKCE) strengthens the code flow by binding the authorization request to the token exchange. The client generates a random verifier, sends its hash as a code_challenge, and later proves possession of the verifier. Without PKCE, a malicious application that captures the redirect on a shared device could exchange the stolen code for tokens; the verifier closes that gap by proving the same client that started the flow is the one completing it. This prevents an attacker who intercepts the authorization code from redeeming it, and it is recommended for all client types, including public ones such as mobile and single-page apps.
Other Grant Types
- Client credentials: for machine-to-machine access where no user is involved.
- Device authorization: for input-constrained devices such as televisions, where the user authorizes on a separate device.
- Implicit and password grants: older approaches that are discouraged because they expose tokens or handle credentials directly; prefer the authorization code flow with PKCE.
Common Pitfalls and Defenses
Most OAuth vulnerabilities come from a handful of implementation mistakes.
- Weak redirect URI validation. Accepting loosely matched redirect URIs lets attackers steal codes or tokens. Register exact URIs and match them strictly.
- Missing state parameter. The
statevalue protects the redirect against cross-site request forgery. Generate it randomly and verify it on return, a concern related to CSRF. - Skipping token validation. Resource servers must validate access tokens, and clients must validate ID token signatures, issuer, and audience before trusting them.
- Over-broad scopes. Request the minimum scopes needed so a leaked token grants as little as possible.
- Leaking tokens. Keep tokens out of URLs, logs, and browser storage where scripts can reach them, and prefer secure, HttpOnly cookies or protected storage.
For passwordless authentication that resists phishing entirely, OIDC deployments often pair with WebAuthn and passkeys at the authentication step.
Key Takeaways
- OAuth 2.0 handles delegated authorization, while OpenID Connect adds authentication through an ID token.
- The core roles are resource owner, client, authorization server, and resource server, exchanging access, refresh, and ID tokens.
- The authorization code flow with PKCE is the recommended and most secure choice for nearly all clients.
- Strict redirect URI matching and a verified
stateparameter prevent code interception and CSRF. - Validate every token, request minimal scopes, and never use OAuth access tokens as proof of identity.