OpenID Connect
OpenID Connect (OIDC)
Section titled “OpenID Connect (OIDC)”Standards
Section titled “Standards”- OpenID Connect Core 1.0
- OpenID Connect Discovery 1.0
- OpenID Connect Dynamic Client Registration 1.0
- RFC 7591 / RFC 6750 / RFC 7523 (as used by registration and
private_key_jwt)
Available Flows
Section titled “Available Flows”| Flow ID | Name | Description |
|---|---|---|
oidc_authorization_code |
Authorization Code | OIDC authentication with ID token |
oidc_hybrid |
Hybrid Flow | Combined code + token response (Section 3.3) |
oidc_implicit |
Implicit (Legacy) | Browser-based OIDC flow |
oidc_userinfo |
UserInfo | Claims retrieval from the UserInfo endpoint |
oidc_discovery |
Discovery | OpenID Provider metadata and JWKS resolution |
interaction-code |
Interaction Code | Interactive authorization with PKCE |
Demo Scenarios
Section titled “Demo Scenarios”- Login with OpenID Connect – Full OIDC authentication flow
- ID Token Deep Dive – Token decoding and claims inspection
- Discovery Document Exploration – Provider metadata resolution
Endpoints
Section titled “Endpoints”| Path | Methods | Purpose |
|---|---|---|
/.well-known/openid-configuration |
GET | Discovery document at the issuer root (canonical path a Relying Party derives from the issuer, OIDC Discovery 1.0 Section 4) |
/oidc/.well-known/openid-configuration |
GET | Discovery document (prefixed alias, same content) |
/oidc/.well-known/jwks.json |
GET | JSON Web Key Set (RSA and EC signing keys; OKP/Ed25519 is held in the OP key set but not published here because discovery only advertises RS256 for ID Tokens) |
/oidc/jwks |
GET | JWKS alias |
/oidc/authorize |
GET, POST | Authorization endpoint |
/oidc/token |
POST | Token endpoint (returns ID token) |
/oidc/userinfo |
GET, POST | UserInfo endpoint |
/oidc/register |
POST | Open Dynamic Client Registration (OIDC Dynamic Client Registration 1.0) |
/oidc/register/{client_id} |
GET, PUT, DELETE | RFC 7592 Client Configuration Endpoint (Bearer registration access token) |
/oidc/third-party/initiate |
GET, POST | ProtocolSoup initiator that redirects to an RP initiate_login_uri (not a standardized OP endpoint) |
/oidc/admin/rotate-keys |
POST | Operator-only OP signing-key rotation (disabled unless OIDC_KEY_ROTATION_TOKEN is set) |
What To Validate
Section titled “What To Validate”- ID token claims:
iss,sub,aud,exp,iat,auth_time,nonce,at_hash,c_hash,acr,amr - Discovery fields:
issuer,authorization_endpoint,token_endpoint,jwks_uri - JWKS: RSA/EC key type, algorithm, and key ID alignment with the token header (
kid) - UserInfo: scope-dependent claims, subject consistency with ID token; signed responses include
iss(OP issuer) andaud(RP client ID) - Hybrid: multiple response types in a single authorization request
Request Handling Notes
Section titled “Request Handling Notes”- Authorization errors after
client_idandredirect_uriare validated are returned to the client by redirect (query for the code flow, fragment for implicit and hybrid), echoingstate(RFC 6749 Section 4.1.2.1). Invalidclient_idorredirect_uriis shown to the user agent and never redirected. prompt=nonereturnslogin_requiredwhen no end-user session is present;prompt=loginand an exceededmax_ageforce re-authentication and setauth_time.- The interactive login page includes a Cancel control in its own form
(separate from Sign In). Submitting it redirects to the registered
redirect_uriwitherror=access_denied(and echoesstate/iss) so relying parties can treat user rejection as a normal OAuth/OIDC error (OIDC Core §3.1.2.6, RFC 6749 §4.1.2.1). An existing OP session that completes authorization returns a code instead ofaccess_denied. - RFC 9126 PAR handles (
request_urivalues underurn:ietf:params:oauth:request_uri:) stay redeemable across repeated visits to/oidc/authorizeuntil authorization completes. The OP consumes the handle only when it issues the authorization response, not when the login page is first shown (FAPI 2.0 Security Profile §5.3.2.2 Note 3). PAR-backed authorize requests never silently finish via an existing session cookie. When a session is already present, the OP shows a Continue confirmation (no password fields) so a browser preload or password-manager auto-submit cannot complete the first visit; authorization proceeds only after an explicit Continue (or a fresh password login when no session exists). - Public clients must use PKCE: an authorization code request without a
code_challengeis rejected (RFC 7636 Section 4.4.1). - Authorization codes are bound to the client they were issued to; a different
client redeeming a code is rejected with
invalid_grant. - Authorization codes are single-use. Replaying a code is rejected with
invalid_grantand additionally revokes the access (and refresh) tokens that code already issued; the revoked access token is then rejected at UserInfo with401 invalid_token(RFC 6749 Section 4.1.2, RFC 6750 Section 3.1). - A token-endpoint client-authentication failure made over HTTP Basic returns
401with aWWW-Authenticate: Basicchallenge, and token-endpoint errors do not carry a Bearer challenge (RFC 6749 Section 5.2). - The authorization endpoint accepts requests by both
GETandPOST(OIDC Core 1.0 Section 3.1.2.1). APOSTcarrying authorization parameters is handled identically toGET; the interactive login form posts to the same path and is distinguished internally. - When the flow issues an access token (the code flow always does, as do the
id_token tokenand hybrid flows), the scope-requested claims (profile,email, …) are served from the UserInfo endpoint and are not duplicated in the ID token. They appear in the ID token only for theresponse_type=id_tokencase, where no access token is issued (OIDC Core 1.0 Section 5.4). - The UserInfo endpoint accepts the access token in the
Authorization: Bearerheader or, for a form-encodedPOST, in anaccess_tokenbody parameter (RFC 6750 Section 2). Presenting both in one request is aninvalid_request. - By-value
requestobjects are not supported and are rejected withrequest_not_supported(OIDC Core 1.0 Section 6.3.1). Discovery always advertisesrequest_parameter_supportedasfalse. HTTPSrequest_uriRequest Objects (OIDC Core §6.2) are available only when Dynamic Client Registration is enabled (request_uri_parameter_supported); otherwise they are rejected withrequest_uri_not_supported. Separately, RFC 9126 PARrequest_urivalues (urn:ietf:params:oauth:request_uri:…) are always accepted and merged at/oidc/authorize. Authorization error responses for unsupported or invalid request objects are delivered to the validated redirect URI using the requestedresponse_modeand echostate(RFC 6749 Section 4.1.2.1). When a by-value request object carriesresponse_modeandstateinside the JWT, the OP reads only those two delivery values from the object (without verifying it or using any other claim) so the error reaches the client in the correct channel, for example as aform_postPOST. - The authorization response is delivered in the requested
response_mode:query,fragment, orform_post, all advertised inresponse_modes_supported.queryis rejected for response types that return tokens in the front channel. Forform_postthe OP returns a self-submitting HTML form thatPOSTs the response parameters (success or error) to the redirect URI, so nothing is placed in a URL (OAuth 2.0 Form Post Response Mode). This enables the Form Post OP profiles. - The
claimsrequest parameter is supported (OIDC Core 1.0 Section 5.5), and discovery advertisesclaims_parameter_supportedastrue. Claims requested under theuserinfomember are returned from the UserInfo endpoint; claims requested under theid_tokenmember are returned in the ID token. Every returned value is real data from the user record, and a value the user does not have is omitted rather than erroring (Section 5.5.1). Aclaimsvalue that is not a valid JSON object is rejected withinvalid_request. - The
profilescope returns the full profile standard-claim set from UserInfo (name,given_name,family_name,middle_name,nickname,preferred_username,profile,picture,website,gender,birthdate,zoneinfo,locale,updated_at). Every value is real data held on the demo user record, not synthesised per request (OIDC Core 1.0 Section 5.4). - The
addressandphonescopes are also supported and advertised inscopes_supported. Theaddressscope returns the structuredaddressclaim (OIDC Core 1.0 Section 5.1.1) as a JSON object with the populated members (formatted,street_address,locality,region,postal_code,country); blank members are omitted. Thephonescope returnsphone_numberandphone_number_verified(Section 5.1). All values are real data held on the demo user record. - ID tokens carry
acrandamrdescribing the authentication that actually happened: single-factor password, reported asacrurn:protocolsoup:ac:passwordandamr["pwd"](OIDC Core 1.0 Section 2, RFC 8176). That value is advertised inacr_values_supported. The OP reports the context it genuinely performed and never echoes a higher assurance level (1,2, …) requested viaacr_valuesthat it did not satisfy. - ID tokens are signed with RS256 only; the discovery metadata advertises only what the OP delivers.
Dynamic Client Registration
Section titled “Dynamic Client Registration”Open Dynamic Client Registration is enabled by default
(OIDC_DYNAMIC_REGISTRATION_ENABLED=true). Registrations are ephemeral ordinary
clients: TTL-bounded, capacity-capped, and rate-limited. They receive no
privileges beyond a normal client registration.
POST /oidc/registerContent-Type: application/json
{ "redirect_uris": ["https://rp.example.com/callback"], "client_name": "Example RP", "token_endpoint_auth_method": "private_key_jwt", "jwks_uri": "https://rp.example.com/jwks.json", "initiate_login_uri": "https://rp.example.com/login", "userinfo_signed_response_alg": "RS256", "logo_uri": "https://rp.example.com/logo.png", "policy_uri": "https://rp.example.com/policy", "tos_uri": "https://rp.example.com/tos"}Successful responses are 201 application/json with Cache-Control: no-store,
the registered/defaulted metadata, a unique client_id, credentials when
required, HTTPS registration_client_uri, and an opaque
registration_access_token. Unknown metadata is ignored. Invalid understood
metadata returns 400 with invalid_client_metadata or invalid_redirect_uri.
GET /oidc/register/{client_id} with Authorization: Bearer <registration_access_token> returns the current registration (200).
PUT accepts a complete replacement registration: it must contain the same
client_id, may not contain response-only management fields, and must include
the current client_secret for confidential clients. A successful update
returns 200 and rotates the registration access token. DELETE deprovisions
the client and returns 204 No Content; its client ID, secret, and registration
access token are no longer usable. These management operations follow RFC 7592
Section 2.
Supported token authentication methods include client_secret_basic,
client_secret_post, private_key_jwt, and none. Dynamically registered
clients may request signed UserInfo (userinfo_signed_response_alg=RS256) and
signed Request Objects by reference (request_uri) verified against
jwks/jwks_uri. They may request subject_type: "pairwise"; the OP derives
the subject deterministically from the user and sector, and returns that same
subject in ID Tokens, access tokens, refresh tokens, and UserInfo. For multiple
redirect URI hosts, a pairwise client must supply an HTTPS
sector_identifier_uri. At registration time the OP fetches its JSON array
without following redirects, rejects private-network addresses, and requires it
to contain every registered redirect URI (OIDC Core §8.1; OIDC Registration
§5). Unsigned ID Tokens, unsigned Request Objects, and by-value request
objects are not advertised and are rejected when explicitly requested.
Third-Party Initiated Login
Section titled “Third-Party Initiated Login”OIDC Core §4 sends iss (required, HTTPS), optional login_hint, and optional
target_link_uri from an initiating party to the RP’s registered
initiate_login_uri. Those parameters are not authorization-request parameters
for the OP, so /oidc/authorize does not validate iss or target_link_uri.
ProtocolSoup exposes /oidc/third-party/initiate as a demonstration initiator.
It selects a registered client, redirects only to that client’s HTTPS
initiate_login_uri, and appends the Core §4 parameters. Non-HTTPS
initiate_login_uri values are rejected at registration with
invalid_client_metadata. The RP remains responsible for accepting the request
and starting its own Authentication Request.