OAuth

OAuth 2.0 vs OpenID Connect — What is Actually Different?

OAuth 2.0 answers "can this app access your data?" OpenID Connect answers "who are you?" OIDC is an identity layer built on top of OAuth — it adds a standard way to get user identity information alongside access tokens.

OAuth 2.0 — authorization only

OAuth gives your app an access token to call an API on the user's behalf. The token proves the user authorized your app to access specific resources (scopes). OAuth does not tell your app anything about who the user is — just that they granted permission.

# After OAuth, you have an access token
# You can call the API:
GET /api/data HTTP/1.1
Authorization: Bearer eyJhbGc...

# But you do not know WHO authorized this — OAuth does not define that

OpenID Connect — authentication on top

OIDC adds an ID token (a JWT) to the OAuth response. This token contains standard claims about the user's identity — sub (user ID), name, email, picture. OIDC also defines a standard /userinfo endpoint to fetch additional claims.

# OIDC adds id_token to the token response
{
  "access_token": "eyJhbGc...",
  "id_token": "eyJhbGc...", // JWT with user identity claims
  "expires_in": 3600,
  "token_type": "Bearer"
}

# Decoded id_token contains:
{
  "sub": "user123",  // unique user ID
  "name": "Jane Smith",
  "email": "jane@example.com",
  "iss": "https://accounts.google.com",
  "aud": "your-client-id",
  "exp": 1234567890
}

When to use which

ScenarioUse
Machine-to-machine API accessOAuth (client credentials flow)
Let users log in to your appOIDC (authorization code + PKCE)
Access Google Drive on user's behalfOAuth with Google's scopes
Sign in with GoogleOIDC — you get the user's identity
Third-party API integrationOAuth — just need the access token

The scope that signals OIDC

Include openid in your scope to activate OIDC and receive an ID token. Without it, you get plain OAuth — access token only, no identity information.

scope=openid profile email  // OIDC — returns id_token + access_token
scope=read:data             // plain OAuth — returns access_token only
Debug your OAuth errors → OAuthFixer