Skip to main content
OAuth 2.0 & OpenID Connectlesson 4 of 4 · 3 min read

OIDC: Authentication on Top

The shortcut with a hole in it

Plenty of teams shipped a Login with X button by fetching a profile with an access token and trusting whatever came back.

See the hole in that shortcut. Access tokens are not addressed to anybody.

A malicious app that legitimately obtained a token from the same provider can replay it against your login endpoint. If you accept valid token for this person as this is that person, the attacker has just logged in as their own victim. Researchers demonstrated exactly this against production sign-on systems in 2012.

What the ID token adds

Close it with an ID token, which is what OpenID Connect adds. It is a signed token whose claims answer the authentication question directly.

One claim names the provider, one is a stable identifier for the user, one is your own client identifier, one bounds its life, and profile details ride along.

Verify the signature against the provider's published keys and then, decisively, check that your own identifier is the audience. A token minted for any other app fails that check no matter how valid its signature is. A one-time value in your login request binds the token to that request and closes replay.

Treat the mechanics as a small extension of what you already have. Add one scope to a normal authorization code flow and the token response includes an ID token alongside the access token.

Lean on discovery, which makes it plug-and-play. Every provider publishes a well-known address listing its endpoints and where its keys live, which is why one library handles Google, Microsoft and a self-hosted server identically.

Keep the division of labour straight, because interviews lean on it. OAuth answers what the holder may do, so send the access token to your APIs. OpenID Connect answers who logged in, so verify the ID token in your app and never forward it anywhere.

the shape of it
ProviderID tokenwho logged inAccess tokenwhat they may doYour appAn API1. signed for you2. check audience3. scoped4. sent onward
step 1 of 4
One token says who logged in and stays with you; the other says what they may do.

Worked example

A B2B startup ships its first Sign in with Google in two days: the SPA obtains an access token, calls Google's userinfo endpoint, and POSTs the returned email to /login, which starts a session for whatever address comes back. At the next pentest, the tester registers his own innocuous Google app, gets one target employee to try it, takes the access token his app legitimately received, and replays it against the startup's /login. Twenty minutes from setup to full account takeover, no password touched. Jonas, the backend lead, rewrites the whole path: a backend-run authorization code flow with the openid and email scopes, ID token signature verified against Google's JWKS, aud required to equal their own client_id, iss required to be accounts.google.com, and users looked up by the stable sub claim instead of by email, which can change or be re-registered.

OAuth 2.0 & OpenID Connect: wrapping up

In the real world

  • 01In May 2017 a worm spread through a fake app literally named "Google Docs" that requested Gmail scopes over real OAuth; Google said about 0.1 percent of users, roughly a million accounts, authorized it before the app was killed within an hour, and consent screens gained unverified-app warnings as a result.
  • 02Sign in with Google, GitHub, Microsoft, and Apple are all OpenID Connect; Apple went further and required apps that offer any third-party login to also offer Sign in with Apple, enforced from 2020.
  • 03The OAuth 2.1 draft consolidates a decade of hard lessons: the implicit and password grants are removed, and PKCE becomes mandatory for authorization code clients.
  • 04GitHub's authorization codes expire after ten minutes and its fine-grained personal access tokens narrow the old repo-wide scopes down to per-repository permissions.
  • 05Most companies never build an authorization server; they run Okta, Auth0, or self-hosted Keycloak, because getting token issuance, consent, and revocation right is a product in itself.

Questions people ask

What is the difference between OAuth 2.0 and OpenID Connect in one sentence?

OAuth 2.0 issues access tokens that prove what the holder may do with an API, and OpenID Connect adds a verifiable ID token on the same flow that proves who just logged in. If you're building Login with Google, you want OIDC; if you're accessing a user's calendar on their behalf, that's OAuth.

Why is the implicit flow deprecated?

It returned the access token directly in the redirect URL fragment, exposing it to browser history, logs, referrer leakage, and injected scripts, with no client authentication step at all. The authorization code flow with PKCE gives browser and mobile apps the same one-redirect experience while keeping tokens out of URLs, so OAuth 2.1 removes implicit entirely.

Do I need OAuth for my own first-party app talking to my own API?

No. OAuth solves delegation across trust boundaries, and a first-party app, API, and user database all owned by you has no such boundary; plain sessions or your own token issuance are fine. OAuth starts paying for itself when third-party clients appear, or when many of your own apps need single sign-on against one identity service.

Quick review

OAuth 2.0 roles: Resource Owner (user), Client (your app), Authorization Server (Google/GitHub), Resource Server (API)
Authorization Code Flow:
redirect → auth server → user consents → code → exchange for tokens. Safest for server-side apps
PKCE (Proof Key for Code Exchange):
prevents authorization code interception. Required for mobile/SPA with no client secret
Implicit Flow:
deprecated. Tokens returned in URL fragment. Visible in browser history and logs
Client Credentials Flow:
machine-to-machine. No user involved. Service gets token with client ID + secret
Scopes:
define granted access (read:profile, write:messages). Users see scopes on consent screen
OpenID Connect (OIDC):
OAuth 2.0 + ID token (JWT). Adds 'who is this user' on top of 'what can they do'
the trade-off

You stop storing passwords and start depending on someone else's uptime, consent screen, and rate limits. The spec is large, and most incidents come from choosing the wrong flow (implicit, or authorization code without PKCE) rather than from the protocol. Delegated tokens also make revocation a distributed problem instead of a DELETE.

in the room

'Login with Google/GitHub': use OIDC. Third-party API access on behalf of user: OAuth 2.0 Authorization Code + PKCE.