OAuth vs OpenID Connect: Which One Does What
Abhay Khant
Jan 1, 1970 • 5 min read
OAuth vs OpenID Connect: Which One Does What
- OAuth 2.0 answers what may this app access; OpenID Connect answers who is this user
- OIDC is a thin identity layer built directly on top of OAuth 2.0, not a competitor
- The ID token, a signed JWT, is the piece that turns OAuth into login
- Modern deployments use authorization code flow with PKCE on browsers and mobiles alike
The one-sentence difference
OAuth 2.0 is an authorization framework: as [RFC 6749 frames it](https://datatracker.ietf.org/doc/html/rfc6749#section-1), it lets a user grant a third-party application limited access to their resources without handing over a password. [OpenID Connect](https://openid.net/specs/openid-connect-core-1_0.html) is an identity layer that runs on top of OAuth and tells the application who logged in. The confusion is structural rather than accidental: OIDC requests look exactly like OAuth requests because they are OAuth requests, with extra pieces added to carry identity.
A useful mental model: OAuth issues keys to a room; OpenID Connect also checks your badge at the door. An app can hold broad access tokens yet know nothing reliable about the person who approved them until OIDC enters the picture.
What plain OAuth 2.0 provides
[The OAuth 2.0 specification, RFC 6749](https://datatracker.ietf.org/doc/html/rfc6749), defines how a client obtains an access token through flows called grants. The token names scopes, such as read:orders, and the resource server enforces them on every call. Nothing in that exchange guarantees the client learns the user's name, email, or any stable identifier; different providers even reuse user IDs across clients in incompatible ways. OAuth deliberately stayed out of the identity business, which is precisely the gap OIDC fills.
| Grant | Typical use today |
|---|---|
| Authorization code + PKCE | Web apps, SPAs, mobile: the default choice |
| Client credentials | Machine-to-machine calls with no user present |
| Refresh token | Renewing access without re-prompting the user |
| Implicit | Deprecated; legacy browsers only |
| Resource owner password | Deprecated; legacy migrations only |
The deprecation rows are not opinion: [the OAuth security best-current-practice, RFC 9700](https://datatracker.ietf.org/doc/html/rfc9700), formally advises against both, and [PKCE from RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636) is now expected on every browser flow rather than only native apps.
What OpenID Connect adds
Three additions turn OAuth into a login protocol. First, the ID token: a JWT signed by the identity provider whose claims name the authenticated user, with issuer, subject, audience, and expiry fields our [JWT internals guide](/blog/how-does-jwt-work/) dissects in depth. Second, the userinfo endpoint, which returns the same profile data as JSON for clients that prefer fetching it. Third, discovery: a well-known configuration URL publishing the provider's endpoints and keys, specified in [the discovery standard](https://openid.net/specs/openid-connect-discovery-1_0.html), so clients configure themselves instead of hand-copying URLs.
A real ID token, inspected
To make this concrete we generated a genuine RS256-signed ID token during research using nothing but Python and openssl:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImtleS0yMDI2LTA4In0.eyJpc3MiOiJodHRwczovL2F1dGguc2hvcGRlbW8uZXhhbXBsZSIsInN1YiI6InVzZXItNzMxNSIsImF1ZCI6InNob3BkZW1vLXdlYiIsIm5hbWUiOiJTYW0gUml2ZXJhIiwiZW1haWwiOiJzYW1Ac2hvcGRlbW8uZXhhbXBsZSIsImlhdCI6MTc4NzM0NTQ2MCwiZXhwIjoxNzg3MzQ5MDYwfQ.TihF3GABdV_sY4SFeglETdpwuMHaxgL0TI_jLu4rA2uBjiOrqR30D4PcIx5sLZXHCgdpUBxDyToKsN2rd3Wlv8bopAQwNhmVLZxx-k6jyYHK-R2Gi2qDaSwgCHoaZuNCQQqMCkBS9_OPva_aCG0NIWb_CjLP5j3KP-hz9HqK5CIwrHQNKL-7ay9K6TTJE60pamKqUOAk9wieC9gBojqVQiQtN0yYUchyz-Mtq3kIl76a_pfsa3A6M-Aud83Xj9Dm8OGmC9Fuvl5Km8-4N0kNG1nrFGIe4SRX7Kt8zpfQ7KWKWJPPhPAXTeZ0Qvp7KS2vZiEQ_x-r5_MOCIfvlvLYcw
Decoding the first two segments reveals the identity payload riding inside an otherwise ordinary-looking JWT: issuer auth.shopdemo.example, subject user-7315, audience shopdemo-web, plus profile claims and one-hour validity. Note the header's kid field naming which key signed it, a mechanism the [OIDC core specification](https://openid.net/specs/openid-connect-core-1_0.html#KeyRotation) formalizes for key rotation; production providers rotate keys and publish the matching public set at their discovery URL so verifiers stay current. Paste any real ID token into the JWT decoder to run the same inspection on tokens you encounter.
Side by side
| Aspect | OAuth 2.0 | OpenID Connect |
|---|---|---|
| Core question | What may the app access? | Who is the user? |
| Primary artifact | Access token (opaque or JWT) | ID token (always a JWT) |
| Standard | RFC 6749 and friends | OIDC Core, Discovery, more |
| Standalone use | API access, machine auth | Login on top of OAuth |
| User identity claims | None defined | sub, email, profile, etc. |
Mistakes that keep appearing
- Treating an access token as proof of identity; it proves scope grants, not who is present
- Skipping ID token validation: issuer, audience, expiry, and signature all need checking, as [RFC 9700](https://datatracker.ietf.org/doc/html/rfc9700) reiterates for every token type
- Shipping implicit flow out of habit when code-plus-PKCE is strictly safer per RFC 9700
- Mixing up userinfo data and ID token claims after the provider updates one but not the other
The first mistake deserves emphasis because it survives in production systems: accepting any valid access token from anyone as a login is exactly the confusion this article exists to prevent. The verification rules for the JWTs involved mirror what our [token decoding guide](/blog/decode-jwt-token-online/) demonstrates hands-on.
Two protocols, one handshake
OAuth vs OpenID Connect resolves cleanly once you see the layering: OIDC is OAuth wearing a badge checker. Use plain OAuth for delegated API access between machines and services; add OIDC whenever a human logs in and the application must know reliably who arrived. Request code flow with PKCE, validate every ID token against issuer, audience, and clock, and let the discovery document wire the pieces together.


