Tools

OAuth 2.0 and OpenID Connect Explained

Learn how OAuth 2.0 handles authorization and OpenID Connect adds user identity — the standards behind Sign in with Google, SSO, and API access control.

Editorial Team ·
10 min read intermediate

Introduction

Every time you click “Sign in with Google” or “Continue with GitHub,” two protocols are working together to make that happen securely: OAuth 2.0 handles authorization — deciding what the application is allowed to do on your behalf — while OpenID Connect handles identity — proving who you actually are. Together they power the authentication and authorization infrastructure of the modern web. In 2023, Google reported that OAuth-based Sign-In with Google processes over a billion authentication events per day. Yet despite their ubiquity, OAuth 2.0 and OIDC are frequently misunderstood and misimplemented — leading to token leakage, open redirect vulnerabilities, and broken access control. The OWASP API Security Top 10 lists Broken Object Level Authorization (BOLA) and Broken Authentication among the most critical API vulnerabilities, and both often trace back to OAuth implementation errors. Understanding how OAuth 2.0 and OpenID Connect actually work is essential for any developer building or securing modern applications.

What Is OAuth 2.0?

OAuth 2.0 (defined in RFC 6749) is an authorization delegation framework. It answers one question: can this application access this resource on behalf of this user? OAuth 2.0 is explicitly not an authentication protocol — it says nothing about who the user is, only what the application is permitted to do.

The framework defines four roles. The Resource Owner is the user who owns the data. The Client is the application requesting access. The Authorization Server is the identity provider (Google, GitHub, Azure AD, Okta) that authenticates the user and issues tokens. The Resource Server is the API that the client wants to call — it accepts and validates access tokens.

The key innovation of OAuth 2.0 over earlier approaches is scope-limited access tokens: instead of sharing a password, the user explicitly approves a list of scopes (e.g., “read your email,” “post to your calendar”) and the authorization server issues a token that is only valid for those scopes on that resource server, for a limited time.

What Is OpenID Connect?

OpenID Connect (OIDC) is a thin identity layer built on top of OAuth 2.0. It adds the ability for the authorization server to communicate who the authenticated user is — not just what permissions were granted. OIDC introduces two additions:

  • An ID Token: a signed JSON Web Token (JWT) containing identity claims about the user — their unique subject identifier (sub), name, email, and the time of authentication (auth_time).
  • A UserInfo endpoint: a protected API endpoint at the authorization server that the client can call with an access token to retrieve additional user profile claims.

Where OAuth 2.0 alone gives you “this token can read the user’s calendar,” OIDC adds “and this is the user: their ID is 12345, their name is Jane Doe, their email is [email protected].” This is what makes “Sign in with Google” work — Google acts as the OIDC provider, issuing an ID Token that the relying party (your application) can verify to establish the user’s identity.

How OAuth 2.0 and OpenID Connect Work

The Authorization Code flow with PKCE is the current best-practice flow for all applications:

  1. PKCE setup: The client generates a cryptographically random code verifier (43–128 characters), computes its SHA-256 hash as the code challenge, and stores the verifier locally.
  2. Authorization request: The client redirects the user’s browser to the authorization server’s /authorize endpoint with parameters including response_type=code, the requested scope (e.g., openid email profile), a redirect_uri, a state value (CSRF protection), and the code_challenge.
  3. User authentication and consent: The authorization server authenticates the user (password, MFA, SSO) and displays a consent screen listing the requested scopes. The user approves or denies.
  4. Authorization code issued: The server redirects back to the client’s redirect_uri with a short-lived, one-time authorization code and the original state value. The code is only valid for seconds to minutes.
  5. Token exchange: The client’s backend makes a direct server-to-server HTTPS POST to the authorization server’s /token endpoint, exchanging the authorization code plus the original code verifier for tokens. Including the code verifier proves this is the same client that started the flow.
  6. Token response: The authorization server returns an access token (for calling the resource server), an ID Token (if openid scope was requested — for user identity), and optionally a refresh token (for obtaining new access tokens without re-authenticating).
  7. Resource access: The client includes the access token in the Authorization: Bearer <token> header when calling the resource server API.
Authorization Code flow with PKCE: the authorization code travels through the browser but is worthless without the code verifier. The actual token exchange happens server-to-server, keeping tokens out of browser history and referrer headers.
InterSystems Learning's overview of OAuth 2.0 explains the four roles and the authorization code flow clearly — watch how they illustrate the separation between the authorization code (browser-visible) and the token exchange (server-to-server), which is the key security property of the flow.

OAuth 2.0 vs OpenID Connect vs SAML

FeatureOAuth 2.0OpenID Connect (OIDC)SAML 2.0
PurposeAuthorization (API access delegation)Authentication + AuthorizationAuthentication + SSO
Token formatAccess token (JWT or opaque), Refresh tokenID Token (JWT) + Access tokenXML SAML Assertion
TransportJSON over HTTPSJSON over HTTPSXML over HTTP POST/Redirect
Primary use caseAPI access, third-party app authorization”Sign in with Google/Apple/GitHub”Enterprise SSO (ADFS, Okta SAML)
Mobile/SPA supportExcellent (PKCE)Excellent (PKCE + ID Token)Poor (no browser-native support)
Spec complexityMediumMedium (adds ~20 pages to OAuth 2.0)High (XML schema, extensive spec)
Adoption trendUniversal in APIsGrowing — replacing SAML in new appsDominant in legacy enterprise SSO

If your organization still runs XML-based enterprise SSO, see how SAML authentication works for a deeper look at that protocol and why newer apps are migrating away from it.

Real-World Use Cases

Third-party app authorization: When a project management tool asks “can we read your Google Calendar to schedule meetings?”, OAuth 2.0 handles this with the calendar read scope. The user grants access; the app gets an access token scoped only to calendar reads; Google’s resource server validates the token on each API call. The user’s Google password is never shared with the project management tool. For a related look at how mutual authentication works for server-to-server APIs, see mTLS Explained: Mutual TLS for Zero-Trust APIs.

Enterprise Single Sign-On: Organizations configure their identity provider (Azure AD, Okta, Auth0) as an OIDC provider. Employees authenticate once, and all connected SaaS applications accept the ID Token as proof of identity. The OIDC sub claim uniquely identifies the user across applications. When an employee leaves the organization, revoking their account at the IdP immediately blocks access to all OIDC-connected applications.

Machine-to-machine API authorization: The OAuth 2.0 Client Credentials flow (no user involved) lets backend services authenticate to APIs using a client ID and secret, receiving a scoped access token. This is the standard pattern for microservice-to-microservice authorization — each service holds its own client credentials and requests tokens scoped to the specific APIs it needs to call. Access is auditable and revocable per-client without touching other services.

Common Mistakes to Avoid

Using the Implicit flow: The Implicit flow — where tokens are returned directly in the URL fragment after the authorization redirect — is officially deprecated by RFC 9700. URL fragments appear in browser history, are sent in Referer headers to third-party scripts on the page, and can be intercepted in shared environments. All new applications must use Authorization Code with PKCE, including single-page apps and mobile apps. Never implement the Implicit flow in new code.

Skipping state parameter validation: The state parameter in the authorization request must be a cryptographically random, unguessable value that the client verifies on the redirect callback. Failing to validate state enables Cross-Site Request Forgery (CSRF) attacks where an attacker tricks a user into completing an OAuth flow that authorizes the attacker’s account. This is one of the most common OAuth implementation errors.

Storing tokens in localStorage: Access tokens and ID Tokens stored in localStorage are accessible to any JavaScript running on the page — including malicious scripts injected via XSS. Store tokens in memory (for SPAs) or in httpOnly, Secure cookies (for server-rendered apps). An attacker who successfully injects XSS into a page with tokens in localStorage gains full API access without the user’s knowledge.

Not validating ID Token signatures: An ID Token is only trustworthy after verifying its JWT signature against the authorization server’s public keys (available at the /.well-known/jwks.json endpoint). Accepting an ID Token without signature verification means any attacker who can forge a JWT can impersonate any user. Always use a well-tested JWT library that validates signature, expiry (exp), audience (aud), and issuer (iss) claims.

Getting Started

To implement OAuth 2.0 and OpenID Connect correctly:

First, use an existing library — never roll your own OAuth client. For web applications, use a battle-tested OIDC client library: openid-client for Node.js, authlib for Python, spring-security-oauth2 for Java, or platform SDKs from your IdP (Auth0, Okta, Microsoft MSAL). These handle PKCE, state management, token validation, and refresh token rotation correctly.

Second, register your redirect URIs exactly with your authorization server. OAuth 2.0’s security depends on the authorization server only redirecting to pre-registered URIs. Overly permissive redirect URI patterns (e.g., wildcard subdomains) can allow attackers to redirect authorization codes to attacker-controlled endpoints. Register exact URIs only.

Third, implement token refresh with rotation. Refresh tokens are long-lived credentials and must be protected accordingly. Implement refresh token rotation — each use of a refresh token issues a new refresh token and invalidates the old one. Store refresh tokens in an httpOnly cookie or a server-side session, never in browser-accessible storage. For access token encryption in transit, your TLS configuration (see TLS Handshake Explained) provides the transport-layer protection.

Fourth, follow RFC 9700’s security BCP. RFC 9700 (“OAuth 2.0 Security Best Current Practice,” 2025) is the authoritative checklist for modern OAuth deployments. Key requirements include: always using PKCE, using response_mode=form_post instead of fragment, binding tokens to the client’s DPoP key for public clients, and rotating refresh tokens. For the underlying public-key cryptography that JWT signatures depend on, see Public Key vs Private Key: How They Work Together.

FAQ

Common questions — answered in plain English.

What is OAuth 2.0?
OAuth 2.0 is an authorization framework that lets a user grant a third-party application limited access to their resources on another service — without sharing their password. It defines a standardized flow where the resource owner (user) grants access, the authorization server issues tokens, and the client application uses those tokens to call protected APIs.
What is the difference between OAuth 2.0 and OpenID Connect?
OAuth 2.0 is an authorization protocol — it answers 'what can this application do on the user's behalf?' OpenID Connect (OIDC) is an identity layer built on top of OAuth 2.0 that answers 'who is this user?' OIDC adds an ID Token (a signed JWT containing user identity claims) and a UserInfo endpoint to the OAuth 2.0 framework.
What is an access token?
An access token is a short-lived credential (typically a JWT or opaque string) issued by an authorization server that a client application presents to a resource server to prove it has been granted permission to access specific resources. Access tokens have defined scopes (what they allow) and expiry times (how long they are valid).
What is the difference between the Authorization Code flow and the Implicit flow?
The Authorization Code flow is the secure standard: the authorization server issues a one-time code to the redirect URI, which the backend exchanges for tokens over a server-to-server HTTPS call. The Implicit flow (now deprecated) issued tokens directly in the URL fragment, exposing them to browser history and referrer headers. All new applications should use Authorization Code flow with PKCE.
What is PKCE and why does it matter?
PKCE (Proof Key for Code Exchange, RFC 7636) is a security extension for the Authorization Code flow that protects against authorization code interception attacks in mobile and single-page apps. The client generates a random code verifier, hashes it to a code challenge, and sends the challenge with the auth request. Only the client with the original code verifier can exchange the code for tokens.
What is an ID Token in OpenID Connect?
An ID Token is a JSON Web Token (JWT) issued by the authorization server that contains identity claims about the authenticated user — such as their subject identifier (sub), name, email, and the time of authentication. The ID Token is cryptographically signed by the authorization server's private key and must be verified by the client before trusting its claims.

References

  1. [1]
  2. [2]
    OpenID Connect Core 1.0OpenID Foundation, 2014
  3. [3]
  4. [4]
  5. [5]