Design Desk

Security

OAuth 2.0 & OpenID Connect

Letting a third-party app act on your behalf without handing it your password, and why the protocol for that got mistaken for a login system so often that it grew one on top.

SecurityAdvanced7 min readPrerequisites: Authentication vs Authorization, JWT & Sessions

After this lesson, you should be able to:

  • Explain what OAuth's access token proves, a scoped permission was granted, versus what OIDC's ID token proves, who the user is.
  • Diagnose the common mistake of treating a successful OAuth flow as proof of identity, when only the ID token is built for that.
  • Recognize OAuth and OIDC as the same authentication-versus-authorization split, expressed as two named protocol tokens.
  • Identify that an OIDC ID token is typically a JWT, inheriting its no-lookup verification and its revocation limits.

At a Glance

  • A calendar app that wants to read your Google Calendar shouldn't ever see your Google password, it should get a narrow, revocable permission to do exactly that one thing.
  • OAuth 2.0 is delegated authorization: it answers "can this app do X on my behalf," and issues a token scoped to specific permissions, not an identity.
  • OpenID Connect is authentication, built as a layer on top of OAuth: it answers "who is this person," using the same token-exchange flow, which is why the two get conflated constantly, they share a mechanism but answer different questions.

01 The Problem

A calendar-scheduling app wants to read events from a user's Google Calendar to suggest meeting times. The obvious approach: ask the user for their Google email and password, log in as them directly. Now the scheduling app has the user's actual password, can do anything the account allows, read every email, change account recovery settings, not just read calendar events, and there's no way to revoke just the calendar access without changing the password everywhere else that app might have cached it.

What's actually needed: the user grants the scheduling app permission to read calendar events specifically, the app never sees a password, and the permission can be revoked later without touching the user's actual credentials at all.

A separate issue shows up right next to it. A lot of apps also want to know who the user is, so they can create an account or skip a signup form, "Sign in with Google." That's a different question from "can this app read my calendar," but the mechanism answering it, redirect to Google, come back with a token, ended up built on the exact same protocol as the calendar-access case. Two different questions, answered by the same-looking flow, is where the confusion starts.

OAuth answers the first question, delegated permission. OpenID Connect answers the second, identity, layered directly on top of OAuth's mechanics. Confusing them is confusing "this app can act on your behalf" with "this app knows who you are," and a system that only checks one when it needed the other has a real security gap, not a naming nitpick.

02 What It Is

OAuth 2.0 is a delegated authorization protocol. A user, through their browser, grants a third-party app a scoped permission, a "scope," like calendar.read, without giving the app their password. The app ends up with an access token, a credential proving "this token is allowed to do X, on behalf of this user, at this provider," and that token is what the app presents to the provider's API on every subsequent request. The access token says nothing about who the user is. It's not an identity document, it's a permission slip.

OpenID Connect (OIDC) is an identity layer built on top of OAuth. It adds a specific kind of token, an ID token, which is about identity, a signed, verifiable claim of who the user is, typically a JWT. The rest of the flow, the redirect, the consent screen, the token exchange, is the same OAuth machinery. OIDC just adds this one token type and a specific set of claims. That reuse is exactly why the two get conflated: an app doing "Sign in with Google" and an app that got permission to read your calendar go through a visually identical flow, but one ends with an identity claim, the other with a permission grant.

The actual hard part isn't implementing either protocol, both have mature, well-tested libraries. It's knowing which one is actually being implemented, and checking the right token for the right question. Using an OAuth access token to answer "who is this user" is a common, real mistake. Access tokens aren't required to be interpretable by the app at all, some providers hand back an opaque string, and even a readable one carries no guaranteed claim of identity the way an OIDC ID token does.

In Plain Terms

Handing a valet your car key with instructions to park it only, versus handing someone your driver's license to prove who you are, are two different acts even though both involve handing over a small plastic object at a counter. A valet key that starts the car proves you authorized parking, nothing about who's standing there. A license proves identity, nothing about what they're allowed to do with your car. Treating the valet key as identification because someone at the counter accepted it works fine right up until it doesn't.

03 How It Works

Rendering diagram…

The app never sees a password. It gets an access token scoped to exactly one permission, calendar.read, and that token is what it presents to the calendar API, nothing broader.

Rendering diagram…

The same redirect-and-exchange mechanism, but the app requests identity instead of a permission scope, and gets back an ID token, a signed claim of who the user is, not a permission to call an API on their behalf.

04 Trade-offs

 OAuth access tokenOIDC ID token
What it provesThis app is allowed to do X, on this user's behalf, at this providerThis person is who they claim to be, verified by the provider
FormatOpaque or structured, provider's choice, not guaranteed to be readable by the appTypically a JWT, meant to be decoded and verified by the app directly
Used forCalling the provider's API on the user's behalfEstablishing a session or account for the user in the app itself
Common mistakeTreating it as proof of identity, which it was never designed to guaranteeN/A, this is the token actually built for that question

Watch out

It's tempting to treat "the OAuth flow worked, we got a token back" as proof the user logged in successfully. An access token proves the app was granted a specific permission, not that the app knows who granted it. Some providers hand back an opaque token an app can't even read, and even a readable one carries no guaranteed, verifiable claim of identity, that's what the ID token is for. An app checking "did we get an access token" instead of "did we get and verify an ID token" is one integration away from letting anyone who can complete the flow in as any user, since the access token alone was never the thing answering that question.

05 Where You'll Actually See This

Neither case study implements authentication, so neither shows OAuth or OIDC directly. Worth naming: the moment either needed a third party acting on a user's behalf, a customer authorizing a separate app to initiate payments for them, say, this exact delegated-permission shape is what that requires, not a shared password.

Authentication vs authorization is the general version of the split this article is a concrete, standardized instance of. OIDC's ID token is authentication, who this is. OAuth's access token is authorization, what this app can do. The confusion this article covers is the same confusion that article covers, just with real protocol names and a spec behind it.

JWT & Sessions is directly relevant to the ID token specifically: OIDC's ID token is typically a JWT, which means it inherits everything that article covers, a local signature check with no lookup required, and the same revocation problem. An ID token issued before a user's account was compromised is still a valid, verifiable claim of identity until it expires, for the same reason any other JWT is.

None of this matters if the redirect and token exchange this article describes happens over plain HTTP. Encryption and TLS is the assumption underneath the whole flow: an access token or an ID token intercepted in transit is just as usable to an attacker as one obtained by tricking the consent screen, and no amount of careful scoping or revocation design helps a token that was handed to an eavesdropper before it ever reached the app.

How to reason about it

When asked to explain OAuth versus OIDC, don't just say "OIDC is built on top of OAuth." Say what each token actually proves: an access token proves a scoped permission was granted, an ID token proves who the user is. An answer that doesn't name which specific token to check for a "who is this user" question has described the relationship between the two protocols without describing how to actually use them correctly.

06 Quick Check

An app integrates 'Sign in with Google' purely by checking that it successfully received an OAuth access token after the redirect flow completed, without requesting or verifying an ID token. What's the actual risk in this implementation?