OpenID Connect
ActiveOpenID Connect (OIDC) 1.0 is an identity layer built on top of OAuth 2.0. Where OAuth 2.0 answers 'what can this token access?', OIDC answers 'who is the user?'. OIDC adds an ID Token (a signed JWT) containing user identity claims to the standard OAuth 2.0 token response. Every major identity provider uses OIDC: Google, Apple, Microsoft, GitHub, Auth0, Okta.
In one line
OpenID Connect 1.0 (OpenID Foundation, 2014) is an identity layer on OAuth 2.0. It adds an ID Token – a signed JWT containing user identity claims (sub, email, name, picture). The UserInfo endpoint returns additional claims. Discovery (/.well-known/openid-configuration) publishes the provider's endpoints and capabilities. OIDC is implemented by Google, Apple, Microsoft Azure AD, GitHub, Auth0, Okta, and every modern identity provider.
Quick Reference
| Field | Size | Description |
|---|---|---|
| ID Token | Signed JWT | A JWT containing identity claims about the authenticated user. Signed by the identity provider's private key. Clients verify the signature using the provider's public keys (jwks_uri). Contains sub (user ID), iss (issuer), aud (client_id), exp, iat. |
| Scope: openid | Required | Adding 'openid' to the OAuth scope requests an ID Token in addition to the access token. Without 'openid', you have plain OAuth 2.0 (authorization only, no identity). |
| UserInfo endpoint | GET /userinfo | Returns additional claims about the authenticated user. Protected by the access token (Bearer). Returns name, email, picture, locale, etc. depending on requested scopes (profile, email, address, phone). |
| Discovery | /.well-known/openid-configuration | JSON document published at a well-known URL. Lists all provider endpoints: authorization_endpoint, token_endpoint, userinfo_endpoint, jwks_uri, supported scopes, response types, signing algorithms. |
| JWKS | /.well-known/jwks.json | JSON Web Key Set – the provider's public keys for ID Token signature verification. Clients fetch this to verify ID Token signatures locally without calling the provider. |
| Nonce | Anti-replay parameter | Random value included in authorization request and embedded in ID Token. Client verifies nonce in token matches what was sent. Prevents replay attacks on ID Tokens. |
| at_hash | Access token hash | Hash of the access token embedded in the ID Token. Binds the ID Token to the specific access token – prevents token substitution attacks. |
| Claims scopes | profile/email/address/phone | Additional claims requested by scope: 'profile' (name, given_name, family_name, picture, locale, etc.), 'email' (email, email_verified), 'address', 'phone'. User consents to each scope. |
Key Characteristics
Identity, not authorization
OIDC answers 'who is this user?' OAuth 2.0 answers 'what can this token do?'. They work together: OIDC identity + OAuth 2.0 authorization = complete auth solution.
Federated SSO
Log in once with Google/Apple/Microsoft and access any app that trusts that provider. The user's password never touches your app. Identity provider handles credential management.
Local token verification
ID Tokens are self-contained JWTs. Clients verify them locally using the provider's public keys (jwks_uri) without a network call. Access tokens may still require introspection.
Don't use access token for identity
Never use an OAuth 2.0 access token to identify users. Access tokens are for resource access, not identity. Use the ID Token sub claim as the stable user identifier.
Message Format
# OIDC authorization request (adds openid scope)
GET https://accounts.google.com/o/oauth2/v2/auth?
response_type=code
&client_id=your-client-id.apps.googleusercontent.com
&redirect_uri=https://app.example.com/callback
&scope=openid+email+profile
&state=random-csrf-token
&nonce=random-nonce-value
&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256
# Discovery document (auto-populated from well-known URL)
GET https://accounts.google.com/.well-known/openid-configuration# Token response includes ID Token
{
"access_token": "ya29.a0AfB_byC...",
"token_type": "Bearer",
"expires_in": 3599,
"id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFiZDY4NWY1ZThmZmU0YzE2MDU2NzVkNDhlOTg1ZTlhOWQ5ZmNhZmUifQ...",
"scope": "openid email profile"
}
# ID Token decoded (header.payload.signature)
# Payload:
{
"iss": "https://accounts.google.com",
"sub": "110248495921238986516", // stable user ID – use this
"aud": "your-client-id.apps.googleusercontent.com",
"exp": 1721912400,
"iat": 1721908800,
"nonce": "random-nonce-value", // verify this matches
"email": "[email protected]",
"email_verified": true,
"name": "Alice Example",
"picture": "https://lh3.googleusercontent.com/...",
"at_hash": "HK6E_P6Dh8Y93mRNtsDB1Q"
}