Implementing OpenID Connect (OIDC)
1. Understanding OIDC vs OAuth 2.0
| Aspect | OAuth 2.0 | OIDC |
|---|---|---|
| Purpose | Authorization (delegated access) | Authentication + identity |
| Token | access_token (opaque to client) | + id_token (JWT about user) |
| Scope | API-specific | Adds openid required |
| Endpoints | /authorize, /token | + /userinfo, /discovery |
2. Using ID Tokens
| Claim | Meaning |
|---|---|
| iss | Issuer URL |
| sub | Stable user identifier |
| aud | Client ID |
| exp / iat | Validity window |
| nonce | Echoes request nonce — replay protection |
| auth_time | When authentication occurred |
| acr / amr | Authentication Context Class / Methods References |
| at_hash | Hash of access_token (binding) |
3. Understanding OIDC Flow
1. /authorize?scope=openid+profile+email&nonce=N&...
2. User authenticates
3. Redirect with code
4. POST /token → {access_token, id_token, refresh_token}
5. Verify id_token (iss, aud, nonce, sig)
6. Optional: GET /userinfo with access_token for extra claims
4. Requesting UserInfo Endpoint
Example: UserInfo response
GET /userinfo
Authorization: Bearer eyJ...
{
"sub": "user_42",
"email": "alice@example.com",
"email_verified": true,
"name": "Alice Smith",
"picture": "https://cdn/avatars/42.png",
"locale": "en-US"
}
5. Validating ID Tokens
| Check | Detail |
|---|---|
| Signature | Against JWKS key matching kid |
| iss | Matches discovery issuer |
| aud | Contains client_id |
| exp / nbf | Within validity, allow ±60s skew |
| nonce | Matches stored value |
| azp | Equals client_id (if present) |
| at_hash | Matches hash of access_token |
6. Using Standard Claims
| Scope | Claims Returned |
|---|---|
| profile | name, family_name, given_name, middle_name, nickname, preferred_username, profile, picture, website, gender, birthdate, zoneinfo, locale, updated_at |
| email, email_verified | |
| address | address (structured) |
| phone | phone_number, phone_number_verified |
| offline_access | Issue refresh_token |
7. Implementing OIDC Discovery
Example: Discovery document
GET https://issuer/.well-known/openid-configuration
{
"issuer": "https://issuer",
"authorization_endpoint": "https://issuer/authorize",
"token_endpoint": "https://issuer/token",
"userinfo_endpoint": "https://issuer/userinfo",
"jwks_uri": "https://issuer/.well-known/jwks.json",
"end_session_endpoint": "https://issuer/logout",
"response_types_supported": ["code"],
"subject_types_supported": ["public", "pairwise"],
"id_token_signing_alg_values_supported": ["RS256", "ES256"],
"code_challenge_methods_supported": ["S256"]
}
8. Using OIDC Scopes
| Scope | Effect |
|---|---|
| openid | MUST be present — triggers OIDC behavior |
| profile / email / address / phone | Add corresponding standard claims |
| offline_access | Long-lived refresh_token |
9. Implementing Logout Flow
| Spec | Detail |
|---|---|
| RP-Initiated Logout | GET end_session_endpoint?id_token_hint=...&post_logout_redirect_uri=...&state=... |
| Local logout | Clear app session/cookies |
| Global logout | OP clears SSO session + propagates to other RPs |
10. Using Session Management
| Mechanism | Detail |
|---|---|
| check_session_iframe | Polled hidden iframe for session state |
| session_state | Returned with auth response |
| postMessage | iframe → parent: changed/unchanged/error |
| Status (2026) | Mostly superseded by back/front-channel logout |
11. Implementing Front-Channel Logout
| Aspect | Detail |
|---|---|
| Mechanism | OP loads iframe of each RP's frontchannel_logout_uri |
| Requirement | iframe-busting must be disabled for this URL |
| Risk | Browser third-party cookie restrictions can block |
12. Implementing Back-Channel Logout
Example: Logout token (signed JWT from OP)
{
"iss": "https://op.example",
"aud": "client_123",
"iat": 1715000000,
"jti": "uuid",
"sub": "user_42",
"sid": "session-id",
"events": { "http://schemas.openid.net/event/backchannel-logout": {} }
}
| Step | Detail |
|---|---|
| OP POST | Sends logout_token to RP's backchannel_logout_uri |
| RP verifies | Signature, iss, aud, events, sid/sub |
| RP action | Invalidate sessions matching sub/sid |
| Advantage | Server-to-server — bypasses browser cookie issues |