OAuth guides

OpenID Connect: identity on top of OAuth

What OIDC adds to OAuth 2.0, how ID tokens differ from access tokens, and how discovery documents tie it together.

7 min read

OAuth 2.0 answers "can this app access this API on my behalf?" OpenID Connect (OIDC) answers "who signed in?" OIDC is a thin identity layer: it reuses OAuth's authorization and token endpoints and adds standardized identity tokens and a UserInfo endpoint.

OAuth alone vs OIDC

With plain OAuth, an access token might be opaque: your backend has no standard way to know the user's email without calling a vendor-specific profile API. OIDC standardizes:

  • The openid scope, which triggers issuance of an ID token.
  • A signed ID token (JWT) with claims such as sub, iss, aud, and exp.
  • Optional UserInfo for additional profile claims when they are not in the ID token.
  • Discovery at /.well-known/openid-configuration listing endpoints and supported algorithms.

Social login buttons ("Sign in with Google") are almost always OIDC (or vendor extensions on top of it), not raw OAuth with a custom profile fetch.

The ID token

The ID token is a JWT meant for your client, not for arbitrary third-party APIs. Validate it on your server (or use a library that does):

  • Signature against the issuer's JWKS (/.well-known/jwks.json).
  • iss matches the issuer you expect.
  • aud includes your client_id.
  • exp is in the future and iat is reasonable.
  • If you used the authorization code flow, check nonce when you sent one on the authorize request.

Do not send the ID token to your own REST APIs as if it were an access token. APIs should accept access tokens scoped to them; user identity for your session usually comes from claims you extracted after validating the ID token at login time.

Discovery document

Fetching {issuer}/.well-known/openid-configuration returns JSON with authorization_endpoint, token_endpoint, userinfo_endpoint, jwks_uri, and supported scopes and response types. Libraries use this so you configure an issuer URL instead of hard-coding five endpoints per provider.

Issuer strings must match exactly between discovery, ID token iss, and your configuration. Trailing slashes and HTTP vs HTTPS mismatches are a common source of "invalid issuer" errors during local testing.

When to call UserInfo

The UserInfo endpoint returns claims about the authenticated user when presented with a valid access token (not the ID token). Many providers put email and name in the ID token for convenience; others require a UserInfo call or separate scopes such as email and profile.

For server-rendered apps, you typically validate the ID token once at callback, create a session, and only re-fetch UserInfo when you need refreshed profile data.

Scopes and claims

Scopes are strings you request on authorize (openid profile email). Claims are name/value pairs in tokens or UserInfo (sub, email_verified). The openid scope is required for OIDC; profile and email are optional standard scopes that map to standard claim names.

Providers differ on which claims appear without extra consent screens. Read each vendor's documentation for required scopes and for whether email is always verified in the claim you receive.