Zuplo
API Authentication

OpenID vs OAuth 2.0 vs OIDC: Which Auth Protocol Should Your API Use?

Nate TottenNate Totten
May 11, 2026
13 min read

Understand the differences between OpenID, OAuth 2.0, and OpenID Connect (OIDC), and learn which protocol fits your API's authentication and authorization needs.

If you have ever tried to explain the difference between OpenID, OAuth, and OIDC to a coworker, you know how quickly the conversation spirals. The names are confusingly similar, the specs overlap, and most blog posts muddy the water by treating them as interchangeable. They are not.

Each protocol solves a distinct problem. OAuth 2.0 handles authorization — what an application is allowed to do. OpenID Connect (OIDC) adds an authentication layer on top of OAuth 2.0 — proving who the user is. And the original OpenID (versions 1.0 and 2.0) is a now-deprecated predecessor that OIDC replaced entirely.

Getting this wrong means choosing the wrong token type, trusting the wrong claims, or building auth flows that break the moment you add a second identity provider. This guide walks through each protocol, explains when to use what, and shows how they fit into a modern API gateway.

Quick reference: OpenID vs OAuth 2.0 vs OIDC

Before diving into the details, here is a high-level comparison of the three protocols you will encounter in discussions about API auth.

OpenID 1.0 / 2.0 (deprecated)

  • Purpose: Decentralized single sign-on (SSO) for the web
  • Status: Deprecated by the OpenID Foundation. No major provider supports it today.
  • Replaced by: OpenID Connect

OAuth 2.0 (RFC 6749)

  • Purpose: Delegated authorization — letting an app access resources on behalf of a user without sharing credentials
  • Core tokens: Access token, refresh token
  • Does not define: A standard way to get user identity

OpenID Connect (OIDC) (Core 1.0 spec)

  • Purpose: Authentication — verifying who the user is — built as a layer on top of OAuth 2.0
  • Core tokens: ID token (a JWT), plus the OAuth 2.0 access token and refresh token
  • Key additions: /.well-known/openid-configuration discovery, standardized claims (sub, email, name), UserInfo endpoint

The short version: OAuth 2.0 answers “What can this app do?” OIDC answers “Who is this user?” Old OpenID answered the same identity question, but OIDC does it better by building on OAuth 2.0 instead of reinventing the wheel.

OAuth 2.0: delegated authorization

OAuth 2.0 is an authorization framework defined in RFC 6749. It lets a user grant a third-party application limited access to their resources without handing over their password. The classic analogy is the valet key — it starts the car but cannot open the trunk.

The four roles

OAuth 2.0 defines four participants:

  • Resource owner — the user who owns the data
  • Client — the application requesting access
  • Authorization server — issues tokens after verifying consent
  • Resource server — the API that holds the protected data

Grant types

Different situations call for different flows. OAuth 2.0 defines several grant types:

  • Authorization Code — the standard for web and mobile apps. The client redirects the user to the authorization server, receives a short-lived code, and exchanges it for tokens server-side.
  • Authorization Code with PKCE — adds a code verifier to protect public clients (SPAs, native apps) from authorization code interception. RFC 7636 defines this extension, and it is now recommended for all clients — not just public ones.
  • Client Credentials — for server-to-server communication where no user is involved. The client authenticates with its own credentials and receives an access token directly. This is the go-to pattern for machine-to-machine (M2M) integrations, data pipelines, and backend services.
  • Device Code — for devices with limited input capabilities (smart TVs, CLI tools) that cannot easily handle browser redirects.

Access tokens and scopes

OAuth 2.0 access tokens are the keys that unlock API resources. They carry scopes — strings like read:users or write:projects — that define exactly what the token holder is allowed to do.

Access tokens are deliberately short-lived (minutes to hours). If one leaks, the blast radius is limited. Refresh tokens let the client obtain new access tokens without re-prompting the user.

One crucial detail: the OAuth 2.0 spec does not define a standard format for access tokens. They can be opaque strings, JWTs, or anything else. The spec also does not define a standard way to convey user identity. That gap is exactly what OIDC fills.

For a deeper dive into OAuth 2.0 implementation, see our developer’s guide to securing your API with OAuth 2.0.

OpenID Connect (OIDC): authentication on top of OAuth 2.0

OpenID Connect is an identity layer built directly on OAuth 2.0. Published in 2014 by the OpenID Foundation, OIDC adds a standardized way for clients to verify the identity of end-users and obtain basic profile information.

The relationship is straightforward: every OIDC flow is an OAuth 2.0 flow with extra parameters. When a client includes openid in the scope parameter of an authorization request, the authorization server returns an ID token alongside the access token.

The ID token

The ID token is a JWT that contains claims about the authenticated user. Standard claims defined by the OIDC Core spec include:

  • sub — a unique identifier for the user
  • iss — the issuer (your identity provider)
  • aud — the intended audience (your application’s client ID)
  • exp — expiration timestamp
  • iat — issued-at timestamp
  • nonce — ties the token to a specific authentication request (prevents replay attacks)
  • email — the user’s email address
  • name — the user’s display name

Because the ID token is a signed JWT, the client can verify it locally by checking the signature against the provider’s public keys — no network call required.

Discovery and JWKS

OIDC standardizes how clients find provider configuration through a well-known discovery endpoint:

plaintext
https://your-idp.com/.well-known/openid-configuration

This document tells clients everything they need: the authorization endpoint, token endpoint, supported scopes, signing algorithms, and crucially, the JWKS URI — the URL where the provider publishes the public keys used to sign tokens.

The JSON Web Key Set (JWKS) endpoint, defined in RFC 7517, returns the current set of public keys. Clients and API gateways cache these keys and use them to verify JWT signatures without calling the identity provider on every request.

The UserInfo endpoint

OIDC also defines a /userinfo endpoint that returns additional claims about the authenticated user. While the ID token contains a minimal set of claims, the UserInfo endpoint can return richer profile data — useful when the client needs information beyond what fits in a compact token.

Why the original OpenID is gone

OpenID 1.0 (2005) and OpenID 2.0 (2007) were early attempts at decentralized web authentication. The idea was simple: use a URL as your identity and let any site verify it against an OpenID provider.

The protocol had real traction for a while — major sites including Google, Yahoo, and Stack Overflow supported it. But it had limitations that became deal-breakers as the web evolved:

  • No built-in authorization — OpenID only handled “who are you?” without a mechanism for “what are you allowed to do?”
  • Poor mobile support — the redirect-based flow assumed desktop browsers
  • Limited profile data — getting user attributes required nonstandard extensions
  • Fragmented ecosystem — different providers implemented extensions inconsistently

Google deprecated OpenID 2.0 support in 2015. The OpenID Foundation officially classified OpenID 2.0 as obsolete, publishing a migration guide for moving to OIDC. By 2019, virtually all major providers had dropped support.

OIDC solved every shortcoming by building on OAuth 2.0’s battle-tested authorization framework and adding identity on top. It is the clear successor, and “OpenID” in modern usage almost always means OpenID Connect.

When to use which protocol

Choosing the right protocol depends on what your API actually needs to know.

OAuth 2.0 alone: third-party apps accessing your API

Use OAuth 2.0 when a third-party application needs to access your API on behalf of a user. The application does not need to know who the user is — it just needs a token that proves the user said “yes, this app can read my data.”

Typical scenarios:

  • A Slack bot reading a user’s calendar events
  • A CI/CD pipeline deploying to your infrastructure
  • A third-party analytics dashboard pulling usage metrics

OIDC: federated login and identity claims

Use OIDC when your application or API needs to verify user identity — not just authorization. OIDC gives you a standardized ID token with claims you can trust, issued by a provider like Auth0, Okta, Azure AD (Entra ID), or Google.

Typical scenarios:

  • Single sign-on (SSO) across multiple applications
  • A gateway that routes requests or applies policies based on user identity
  • Any API that needs to know who is calling, not just what they are allowed to do

Client Credentials: server-to-server and agent-to-API

Use the OAuth 2.0 Client Credentials grant when there is no user in the picture — just two machines talking to each other. The client authenticates with its own credentials (client ID and secret) and receives an access token directly.

Typical scenarios:

  • A backend microservice calling another internal API
  • A data pipeline pulling records from your API on a nightly schedule
  • An AI agent making autonomous API calls with its own identity

Summary of when to use each

OAuth 2.0 (Authorization Code / PKCE)

  • Goal: Authorize a third-party app to access user resources
  • User involved: Yes
  • Identity returned: No (unless you also request OIDC scopes)

OIDC

  • Goal: Authenticate a user and get verified identity claims
  • User involved: Yes
  • Identity returned: Yes (ID token with sub, email, name, etc.)

OAuth 2.0 (Client Credentials)

  • Goal: Authenticate a machine or service
  • User involved: No
  • Identity returned: The client itself is the identity

Common confusion: ID tokens are not access tokens

This is the single most common mistake developers make with OIDC, and it creates real security vulnerabilities.

ID tokens prove who the user is. They are intended for the client application — the frontend, the mobile app, the backend that initiated the login. The client reads the claims to personalize the UI, create a session, or make authorization decisions.

Access tokens prove what the holder is allowed to do. They are intended for the resource server (your API). The API validates the access token and uses its scopes to determine what data to return.

Here is why the distinction matters:

  • Never send an ID token to an API as a bearer token. The ID token’s aud claim is your application’s client ID, not your API’s identifier. An API that accepts ID tokens as access tokens is trusting a token that was not issued for it.
  • Never use an access token to determine who the user is in your client app. The access token’s format is not guaranteed by the OAuth 2.0 spec. Even if it happens to be a JWT today, the authorization server can change the format without notice.

The correct pattern: use the ID token in your client to establish a session, and send the access token to your API in the Authorization header.

OIDC at the API gateway

An API gateway is the natural place to validate OIDC tokens. Instead of every microservice implementing its own JWT verification logic, the gateway handles it once, at the edge, before traffic reaches your backend.

What the gateway validates

A properly configured gateway checks every incoming request:

  1. Signature verification — the JWT’s signature is verified against the identity provider’s public keys (fetched from the JWKS endpoint)
  2. Issuer validation — the iss claim must match the expected identity provider
  3. Audience validation — the aud claim must match your API’s identifier
  4. Expiration check — the exp timestamp must be in the future
  5. Claim extraction — verified claims are extracted and passed to downstream services for authorization decisions

JWKS rotation

Identity providers rotate their signing keys periodically. A robust gateway caches the JWKS and refreshes it automatically when it encounters a token signed by an unknown key. This avoids both hitting the provider on every request and breaking when keys rotate.

From authentication to authorization

Once the gateway has verified who the user is (authentication), downstream services can use the extracted claims for what they can do (authorization). Common patterns include:

  • Scope-based access control — checking scope claims against required permissions for each endpoint
  • Role-based access control (RBAC) — mapping a roles claim to allowed operations
  • Claim-driven routing — forwarding requests to different backends based on org_id or tenant claims

How Zuplo integrates with OIDC providers

Zuplo’s approach to OIDC is programmable and provider-agnostic. Token validation runs at the edge across 300+ data centers, so authentication decisions happen close to the caller without a round-trip to a central auth service.

The OpenID JWT Auth Policy

The core building block is the OpenID JWT Auth Policy. It works with any OIDC-compliant identity provider — you point it at a JWKS URL, set the expected issuer and audience, and the gateway handles signature verification, expiration checks, and claim extraction automatically.

JSONjson
{
  "name": "oidc-auth",
  "policyType": "open-id-jwt-auth-inbound",
  "handler": {
    "export": "OpenIdJwtInboundPolicy",
    "module": "$import(@zuplo/runtime)",
    "options": {
      "issuer": "$env(AUTH_ISSUER)",
      "audience": "$env(AUTH_AUDIENCE)",
      "jwkUrl": "https://your-idp.com/.well-known/jwks.json"
    }
  }
}

After successful validation, the token’s claims are available on request.user:

  • request.user.sub — the subject identifier from the JWT
  • request.user.data — all other claims from the token

Provider-specific policies for faster setup

While the generic OpenID JWT policy works with any provider, Zuplo also offers pre-configured policies for common identity platforms:

  • Auth0
  • Okta
  • Clerk
  • AWS Cognito
  • Firebase
  • Supabase

These are convenience wrappers around the same JWT validation logic, with provider-specific defaults already set (like JWKS URLs and issuer formats).

Claim-driven authorization in TypeScript

Because Zuplo is a programmable gateway, you can go beyond declarative policy configuration and write TypeScript to make authorization decisions based on any claim. For example, checking an org_id claim:

TypeScripttypescript
import { ZuploContext, ZuploRequest, HttpProblems } from "@zuplo/runtime";

export default async function (request: ZuploRequest, context: ZuploContext) {
  const orgId = request.user?.data?.org_id;

  if (orgId !== "expected-org-id") {
    return HttpProblems.forbidden(request, context);
  }

  return request;
}

Zuplo also includes a built-in JWT Scope Validation Policy for checking scopes without writing custom code.

API key + JWT on the same route

Real-world APIs often need to support both API keys (for machine clients) and JWTs (for user-facing apps) on the same endpoint. Zuplo handles this with the Composite Inbound Policy, which chains multiple auth policies together. The first policy that succeeds populates request.user, and downstream handlers do not need to know which credential type was used.

For a full walkthrough of this pattern, see Using JWT and API Key Auth on the Same Route.

AI agent authentication and token exchange

As AI agents become first-class API consumers, the authentication model is evolving. Two patterns are emerging.

Client Credentials for autonomous agents

When an AI agent acts on its own behalf — not on behalf of a specific user — the OAuth 2.0 Client Credentials grant is the right fit. The agent authenticates with its own client_id and client_secret, receives a scoped access token, and calls your API. The API sees the agent as a known, authorized machine identity, subject to its own rate limits and permissions.

This is exactly how you would authenticate a backend microservice today. Nothing special is needed on the protocol side.

Token exchange for agents acting on behalf of users

The more interesting case is when an agent needs to call an API on behalf of a specific user. The user has authenticated with the agent, and now the agent needs to prove both its own identity and the user’s identity to a downstream API.

RFC 8693 (OAuth 2.0 Token Exchange) defines a standard mechanism for this. The agent presents its existing token (the subject_token) to the authorization server and receives a new token scoped to the downstream API, with the user’s identity preserved.

This pattern is critical for:

  • Preserving user identity across service boundaries — the downstream API can enforce per-user access policies, not just per-agent ones
  • Audit trails — logs show which user authorized which action, even through multiple layers of delegation
  • Least-privilege access — the exchanged token is scoped to exactly what the downstream API needs

Token exchange is gaining traction in the AI ecosystem. Auth0’s Token Vault implements RFC 8693 specifically for connecting AI agents to third-party services securely. As the Model Context Protocol (MCP) ecosystem matures, expect token exchange to become the standard way agents propagate identity.

Wrapping up

The protocols are distinct, and using the right one matters:

  • OAuth 2.0 handles authorization — granting an app access to resources
  • OIDC handles authentication — verifying who the user is, using OAuth 2.0 as the underlying transport
  • The original OpenID is deprecated and replaced entirely by OIDC
  • ID tokens are for clients; access tokens are for APIs — do not mix them up
  • Client Credentials is the right OAuth 2.0 grant for machine-to-machine and agent-to-API communication
  • Token exchange (RFC 8693) is the emerging pattern for agents acting on behalf of users

At the API gateway level, OIDC validation should happen once, at the edge, before traffic hits your backend. Zuplo’s OpenID JWT Auth Policy makes this straightforward — point it at any OIDC provider’s JWKS endpoint, and the gateway handles signature verification, issuer checks, audience validation, and claim extraction automatically.

If you are building or securing APIs and want to see how this works in practice, sign up for Zuplo and try adding JWT authentication to a route in under five minutes.