OAuth vs Authentication
It's one of the most common mix-ups in web development: OAuth 2.0 is an authorization protocol — it answers 'is this app allowed to do X?' — not an authentication protocol, which answers 'who is this person, verified how?' The confusion is understandable because so many 'Sign in with Google' or 'Sign in with GitHub' buttons visually look like login, and under the hood they do use OAuth machinery, but strictly speaking OAuth 2.0 alone was never designed to prove a user's identity to the client application.
Cricket analogy: Confusing OAuth with authentication is like confusing a stadium entry pass (proves what areas you can access) with the biometric ID check at passport control (proves who you actually are) — a valid gate pass says nothing about your legal identity.
What OAuth 2.0 Actually Proves
An OAuth 2.0 access token only proves that some authorization server granted a client permission to call certain APIs with certain scopes — it does not, on its own, carry a reliable, standardized claim about who the resource owner is. Many access tokens are opaque strings the resource server must look up via an introspection endpoint, and even when they're JWTs, their claims are meant for the resource server's authorization checks (audience, scope, expiry), not for the client to trust as an identity assertion.
Cricket analogy: An access token is like a media pass that proves 'this crew may film the boundary rope' — it says nothing about which specific journalist is wearing it that day, since the stadium gate only checks the pass's validity, not a face match.
Why 'Sign in with Google' Feels Like Authentication
The reason 'Sign in with Google' actually does authenticate the user is OpenID Connect (OIDC), a thin identity layer built directly on top of OAuth 2.0. When a client requests the openid scope, the authorization server returns not just an access token but also an ID token — a signed JWT containing standardized claims like sub (a stable user identifier), iss (issuer), aud (which client it's for), and exp. The client verifies this JWT's signature and claims itself; that verification step is what actually constitutes authentication, and it's an OIDC feature, not a base OAuth 2.0 one.
Cricket analogy: The ID token is like a BCCI-issued, tamper-evident player identity card with a verifiable hologram — unlike a generic ground-access pass, this card is specifically designed to be checked and trusted as proof of who the player is.
// Decoded payload of an OpenID Connect ID token (a JWT, verified via its signature)
{
"iss": "https://accounts.example.com",
"sub": "110169484474386276334",
"aud": "photo_app_123",
"exp": 1751200000,
"iat": 1751196400,
"email": "user@example.com",
"email_verified": true,
"name": "Priya Sharma"
}
// The client MUST verify: signature, iss matches expected issuer,
// aud matches its own client_id, and exp has not passed.The Classic Mistake: Using Access Tokens to Authenticate Users
A well-documented real-world vulnerability class occurs when a backend treats a bare OAuth access token as proof of login: it accepts any valid-looking access token from a client, calls the provider's userinfo or API endpoint to fetch a profile, and logs the user in based on that response — without verifying the token's audience (aud) was actually meant for this application. This is the 'confused deputy' problem: an access token minted for App A can sometimes be replayed against App B's backend if App B doesn't check that the token was actually issued for it, letting an attacker log in as someone else.
Cricket analogy: It's like a stadium gate accepting any valid-looking media pass regardless of which match it was actually issued for — a pass stamped for a domestic T20 gets accepted at a World Cup final gate simply because it 'looks valid,' which is exactly the audience-check failure.
The correct pattern for 'Sign in with X' is to request the openid scope, receive an ID token, cryptographically verify its signature and claims (especially aud and iss), and use the sub claim as the stable user identifier — never derive identity purely from the fact that an access token was accepted by an API call.
Never treat 'I successfully called an API with this access token' as equivalent to 'this user is logged in.' Access tokens can be scoped for narrow purposes, can be replayed across services that don't check audience, and were never designed as identity assertions — only a properly verified OIDC ID token should drive session/login logic.
- OAuth 2.0 is authorization ('what can this app do'); it is not, by itself, authentication ('who is this person').
- A bare access token proves permission to call an API, not a verified user identity.
- OpenID Connect (OIDC) adds authentication on top of OAuth 2.0 via the signed ID token and the
openidscope. - The ID token's
subclaim is the stable identifier a client should use to recognize a user. - Clients must verify an ID token's signature, issuer, audience, and expiry before trusting it.
- Treating any accepted access token as proof of login creates a 'confused deputy' vulnerability if the
audclaim isn't checked. - 'Sign in with Google/GitHub' buttons work because they use OIDC, not raw OAuth 2.0 alone.
Practice what you learned
1. What question does OAuth 2.0 primarily answer?
2. What OIDC artifact is specifically designed to authenticate a user?
3. Which claim in an ID token should a client check to ensure the token was actually issued for its own application?
4. What is the 'confused deputy' problem in this context?
5. Which scope must a client request to receive an OIDC ID token?
Was this page helpful?
You May Also Like
What Is OAuth 2.0?
A plain-English introduction to OAuth 2.0 as a delegated authorization framework, covering why it replaced password sharing and how tokens and scopes work.
OAuth 2.0 Roles and Terminology
A guided tour of the four OAuth 2.0 roles — resource owner, client, authorization server, resource server — and the core vocabulary you'll see in every spec and SDK.
The Authorization Code Flow
A step-by-step walkthrough of OAuth 2.0's most widely used grant type, the authorization code flow, including why PKCE is now required for public clients.
Related Reading
Related Study Notes in Programming
Browse all study notesApache Spark Study Notes
Programming · 30 topics
ProgrammingApache Flink Study Notes
Programming · 30 topics
ProgrammingHadoop Study Notes
Programming · 30 topics
ProgrammingSnowflake Study Notes
Programming · 30 topics
ProgrammingApache Airflow Study Notes
Programming · 30 topics
Programmingdbt (Data Build Tool) Study Notes
Programming · 30 topics