← Open in the full interactive course (progress tracking, search & more)

OAuth answers "what can this app touch on my behalf?" OpenID Connect adds the question OAuth was never built to answer: "who, exactly, is this?"

You've clicked "Sign in with Google" on some third-party website more times than you can count. Think about what actually has to be true for that button to be trustworthy: the third-party site never sees your Google password — you type it, if at all, directly on a Google-controlled page — and yet, seconds later, that third-party site somehow knows exactly who you are and logs you in as yourself. Two genuinely different things happened there, even though it felt like one smooth action: the site was granted some limited access related to your Google account, and the site learned your actual identity. Those are two separate specifications doing two separate jobs, and conflating them is one of the most common — and most consequential — mix-ups in this entire subject.

OAuth 2.0 is fundamentally an authorization and delegation framework — it lets you grant a third-party app limited access to your data on another service, without ever handing that app your password. On its own, it says nothing about who you are. OpenID Connect (OIDC) is an authentication layer built directly on top of OAuth 2.0, specifically to close that gap.

In this lesson: precisely what OAuth 2.0 does and does not provide, exactly what OpenID Connect adds on top of it, the authorization code flow at a conceptual level, and why "Sign in with Google/Microsoft/GitHub" is OpenID Connect in action.

What Is It?

The Simple Explanation

OAuth 2.0 is a standard way for you to grant one application (a third-party "client") limited, specific permission to act on your behalf against another service (a "resource server," like Google Calendar or GitHub's API) — without ever giving that third-party app your actual password for the service it's accessing.

OpenID Connect is a standard, built directly on top of OAuth 2.0's flows and terminology, that adds a reliable way for the requesting application to also learn who you are — your verified identity — something OAuth alone was never designed to provide.

The Technical Definition

OAuth 2.0 defines a protocol for a client to obtain a limited access token, scoped to specific permissions ("scopes"), issued by an authorization server after the resource owner (you) explicitly grants consent — that access token is then presented to a resource server to access data or perform actions. Nothing in that access token is required to identify who the resource owner actually is; it only proves that some authorization was granted, scoped to certain permissions.

OpenID Connect extends this exact same flow with one crucial addition: alongside the access token, the authorization server (now specifically called an identity provider, or IdP, in OIDC terms) also issues an ID token — a JWT (the exact format from the previous lesson) containing standardized claims about the authenticated user's identity, cryptographically signed by the identity provider. The ID token is what actually tells the client application who just authenticated.

OAuth 2.0 alone

OpenID Connect (on top of OAuth)

Why Does It Exist?

The Problem OAuth Solves — Password Sharing With Third Parties

Before delegated authorization standards existed, the only way for a third-party app to act on your behalf against another service was for you to hand it your actual password — a photo-printing app that wants your Google Photos would ask for your Google password directly. That's a serious problem: the third-party app now has full, unrestricted access to your account (not just the photos it actually needs), it can keep working forever unless you change your password, and you have no way to grant it only the specific access it actually requires.

OAuth 2.0 solves this: the third-party app never sees your password at all. You authenticate directly with the service you actually trust (Google), explicitly consent to a narrow, specific set of permissions, and the third-party app receives only a limited access token — scoped, and revocable, without ever touching your credentials.

The Gap OAuth Left Open — And Why OIDC Exists

OAuth was purpose-built for delegated access, not identity — an access token, by design, doesn't have to carry (or even guarantee) any information about who the user is. In practice, many applications adopted OAuth anyway purely as a login mechanism, in inconsistent, non-standardized, sometimes insecure ways, because it was the flow already available. OpenID Connect exists specifically to close that gap properly: a standardized, secure, well-specified authentication layer built directly on OAuth 2.0's proven flows, rather than every application inventing its own ad-hoc convention for "use OAuth to log someone in."

Big Picture

OIDC IS A LAYER ON TOP OF OAUTH, NOT A SEPARATE PROTOCOL
OAuth 2.0 — the base protocol: delegated, scoped access tokens

OpenID Connect — built directly on top, reusing OAuth's flows

Adds: an ID token (a signed JWT of identity claims) alongside the access token

The client application now has both: an access token (what it can do) and an ID token (who the user is)

How It Works

THE AUTHORIZATION CODE FLOW — CONCEPTUAL WALKTHROUGH
1. THE USER CLICKS "SIGN IN WITH GOOGLE" ON A THIRD-PARTY APP
2. THE USER AUTHENTICATES AND CONSENTS — ONLY ON THE IDENTITY PROVIDER'S OWN PAGE
3. GOOGLE REDIRECTS BACK WITH A SHORT-LIVED AUTHORIZATION CODE
4. THE APP'S OWN SERVER EXCHANGES THE CODE FOR TOKENS — SERVER-SIDE, NOT IN THE BROWSER
5. THE APP VALIDATES THE ID TOKEN AND ESTABLISHES A LOCAL SESSION

This lesson deliberately stops at this conceptual level — the full provider-specific mechanics (exact endpoint URLs, PKCE parameters, state validation for CSRF protection, redirect URI registration rules) genuinely vary by identity provider and are out of scope here. What matters is the shape of the flow: credentials are entered only on the identity provider's own page, a short-lived code is exchanged server-side for tokens, and the ID token is what ultimately answers "who is this."

Simple Example

What the ID token actually contains, once decoded — recognizably a JWT, exactly as covered in the previous lesson:

// Decoded ID token payload (base64url-decoded — readable by anyone holding it,
// exactly as the previous lesson established for any standard JWT):
{
  "iss": "https://accounts.google.com",   // issuer — who signed this
  "sub": "110169484474386276334",         // subject — the user's stable, unique ID at this issuer
  "aud": "your-app-client-id",            // audience — which app this token was issued for
  "email": "user@example.com",
  "email_verified": true,
  "name": "Priya Sharma",
  "exp": 1893456000                       // expiration — see the previous lesson
}

Meaning: This is a signed JWT, verified exactly the way the previous lesson described — and it carries the same "signed, not encrypted" property. The access token issued alongside it, by contrast, is what the app would actually send to Google's APIs if it also needed to do something (like read the user's calendar) — the ID token's job is purely to establish who logged in.

Real-World Example

An ASP.NET Core app registering an external OIDC provider — the conceptual flow from "How It Works," expressed as configuration rather than raw HTTP requests:

builder.Services
    .AddAuthentication(options =>
    {
        options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = "OpenIdConnect";
    })
    .AddCookie() // the app's own local session, once OIDC login succeeds
    .AddOpenIdConnect("OpenIdConnect", options =>
    {
        options.Authority = "https://accounts.google.com";     // the identity provider
        options.ClientId = builder.Configuration["Google:ClientId"];
        options.ClientSecret = builder.Configuration["Google:ClientSecret"]; // kept server-side only
        options.ResponseType = "code";                          // the authorization code flow
        options.Scope.Add("openid");                            // required — this is what makes it OIDC, not just OAuth
        options.Scope.Add("email");
        options.Scope.Add("profile");
        options.SaveTokens = true;
    });

Notice the "openid" scope specifically — this is the actual, literal signal in the protocol that turns a plain OAuth request into an OpenID Connect one, telling the authorization server "also issue an ID token, not just an access token." Everything else here — Authority, ClientId, ResponseType = "code" — configures the exact authorization code flow walked through conceptually above, letting the framework's own middleware handle the redirect, the code exchange, and the ID token validation for you.

Analogy

A hotel key card, and a separate ID check at the front desk

OAuth is like a hotel issuing a key card scoped to exactly what it opens — your room, and maybe the gym. The person handing you the card doesn't necessarily need to record who, precisely, you are as a person — the card itself just proves "whoever holds this may open these specific doors." That's authorization: limited, delegated access, with no inherent statement about identity.

OpenID Connect is the front-desk check-in that happens alongside issuing that card — showing your ID, having the hotel verify it's genuinely you, and the hotel recording, reliably, "this specific person is the one who now holds this card." Both things happen through the same overall process at the front desk, but they're answering two different questions: what does this card open, versus who is the person holding it. A plain key card, on its own, never answered the second question — that's precisely the layer OIDC adds.

Under the Hood

WHY THE CODE-FOR-TOKEN EXCHANGE HAPPENS SERVER-SIDE
KEEPING TOKENS AND SECRETS OUT OF THE BROWSER

Common Confusion

1. "OAuth is a login system" — not by itself; this is the single most common mix-up in this entire area

OAuth's access token exists purely to authorize access to a resource — it does not have to identify who's holding it in any standardized, reliable way, and plenty of valid OAuth access tokens carry no usable identity information at all. Many applications historically misused "logging in via Google/Facebook" as if bare OAuth alone were sufficient for authentication, which led to genuine, documented security issues. OpenID Connect exists precisely because OAuth alone is the wrong tool for authentication — the ID token is the specific, standardized piece that makes login safe and reliable.

2. "OIDC is a completely separate protocol from OAuth" — no, it's built directly on top of it

OpenID Connect doesn't reinvent the request/redirect/token-exchange machinery — it reuses OAuth 2.0's flows exactly, and adds the openid scope plus the ID token on top. This is why OIDC configuration in a real app (as in the Real-World Example) looks almost identical to plain OAuth configuration, just with an extra scope and an extra token type in play.

Common Mistakes

Mistake 1 — Treating a bare OAuth access token as proof of identity

Building a "login" feature that only obtains an OAuth access token (no openid scope, no ID token) and simply assumes whoever presented it must be a specific, known user.

Use OpenID Connect specifically for authentication — request the openid scope, and verify the signed ID token it returns, rather than inferring identity from an access token never designed to carry it reliably.

Mistake 2 — Letting the third-party app collect the user's password directly

A "Sign in with Google" flow implemented by prompting the user for their Google password inside your own app's UI, then submitting it to Google yourself.

The user must always authenticate directly on the identity provider's own page (the redirect step) — an app that ever sees the raw password for a service it doesn't own has broken the entire point of the flow.

Mistake 3 — Exchanging the authorization code from client-side JavaScript, exposing a confidential client secret

Performing the code-for-token exchange directly in browser JavaScript, which would require embedding the app's confidential client secret somewhere a user's browser (and anyone inspecting it) could read.

Perform the code exchange on the app's own backend server, where the client secret can be kept genuinely confidential — exactly the flow shown in "Under the Hood."

When Should I Use It?

Rule of thumb: If the question is "can this app touch my data on another service," that's OAuth. If the question is "does this app know, reliably, who I actually am," that requires OpenID Connect's ID token — a bare OAuth access token was never designed to answer it.

Mental Model

OAuth 2.0 = delegated, scoped access — "what can this app do on my behalf?"
OpenID Connect = identity, layered directly on top of OAuth's own flows.
Access token = what OAuth produces. ID token (a JWT) = what OIDC adds.
Authorization code flow = redirect to the identity provider → authenticate there, never in the third-party app → short-lived code → server-side exchange for tokens.

Remember: "Sign in with Google" only works because OIDC's ID token exists — a plain OAuth access token was never built to answer "who is this," and treating it as if it did is the single most common mistake in this area.

Key Takeaway


Check Your Understanding

You've seen exactly what OAuth provides, exactly what gap OpenID Connect closes, and how the authorization code flow keeps credentials safe. Let's check your understanding.

1. Which statement most accurately describes the relationship between OAuth 2.0 and OpenID Connect?

Show answer

Correct: B

Why B is correct: This is the precise, standard relationship — OIDC reuses OAuth 2.0's own flows and adds the openid scope and ID token specifically to provide authentication, which OAuth alone doesn't reliably do.

Why A is incorrect: They are not competitors solving the same problem — OAuth solves delegated authorization; OIDC solves authentication, building directly on OAuth rather than replacing it.

Why C is incorrect: The relationship runs the other direction — OIDC is built on top of OAuth 2.0, not the reverse, and neither replaces the other.

Why D is incorrect: Both specifications work with tokens; the distinction is what each token type is used for (access vs. identity), not passwords vs. tokens.

Reinforcement: OIDC = OAuth's flows + an ID token. Memorize it in exactly that shape.

2. An app obtains a plain OAuth 2.0 access token (no openid scope requested) from a service. Can the app reliably use that token alone to know exactly who the user is?

Show answer

Correct: B

Why B is correct: This is the exact distinction the lesson centers on — an access token authorizes access; it was never designed to be a reliable statement of identity. That's precisely why OpenID Connect exists as a separate addition.

Why A is incorrect: This is the common mistake called out directly in "Common Mistakes" — treating a bare access token as identity proof is not safe or standardized.

Why C is incorrect: Even a JWT-formatted access token is still scoped to authorization, not guaranteed to carry standardized, verified identity claims the way an OIDC ID token specifically does.

Why D is incorrect: Expiration is unrelated to whether a token can identify a user — the issue is what the token was designed to represent, not its lifetime.

Reinforcement: Never infer identity from a bare OAuth access token — that's specifically what the ID token is for.

3. In the authorization code flow, why does the user enter their password only on the identity provider's own page, never inside the third-party app?

Show answer

Correct: B

Why B is correct: This is the foundational problem OAuth was built to solve — eliminating the need to share your password with every third-party app that wants some access, by keeping credential entry confined entirely to the service you actually trust.

Why A is incorrect: This has a real, substantial security purpose, not just a visual one — it's a core design decision of the entire protocol.

Why C is incorrect: Server performance is irrelevant to this design choice.

Why D is incorrect: There's no browser-level technical restriction forcing this — it's a deliberate protocol design choice, not a browser limitation.

Reinforcement: If any flow you're building ever asks a user to type another service's password into your own app's UI, it isn't OAuth/OIDC, and it defeats the entire point of using them.

4. Why is the authorization code exchanged for tokens via a direct server-to-server call, rather than from JavaScript running in the user's browser?

Show answer

Correct: B

Why B is correct: The code-for-token exchange requires the client's confidential secret to prove it's genuinely the registered app. That secret must stay server-side; shipping it to browser JavaScript would expose it to anyone inspecting the page.

Why A is incorrect: Browsers are technically capable of making such requests — the restriction is about credential confidentiality, not a technical limitation.

Why C is incorrect: This is a real, meaningful security boundary, explicitly called out as a common-mistake risk when violated.

Why D is incorrect: Since OIDC reuses OAuth's own flow, this same server-side exchange requirement applies to both — it isn't unique to plain OAuth.

Reinforcement: Anything requiring a confidential secret belongs on the server, never in code shipped to the browser — a general security principle this flow depends on directly.

You now know exactly what "Sign in with Google" is actually doing under the hood — and precisely why OAuth alone could never have been the whole story. Next up: rate limiting, protecting your API's resources from excessive traffic regardless of who's making the request.


dotnetmadeeasy.com — Learn C# and .NET, the right way.