skip to content

Flows and Metadata

The wire side of federated login: which flow runs, what the request asks for, how a client discovers the provider, and how sessions end. Where most integration bugs actually live.

part ofFederated identityoverview, primer and where to startread it →
on this pageshow

questions

16

Given only an issuer URL, how does a relying party find and use the OpenID Provider configuration document?

level: juniorimportance: must knowfreq 58%

answer

  1. one URL in, many endpoints out
  2. a well-known path under the issuer
  3. append it, never insert it
  4. terminating slash removed first
  5. issuer path kept, segment goes after

basics

~10 s

Remove any terminating slash from the issuer URL, then concatenate /.well-known/openid-configuration to it. The JSON object returned carries issuer, authorization_endpoint, token_endpoint, userinfo_endpoint and jwks_uri, so one configured value yields every address the flow needs.

solid answer

~40 s

OpenID Connect Discovery turns one configured value into a whole integration. The Issuer Identifier is an `https` URL with no query or fragment; you strip any terminating `/` and **concatenate** `/.well-known/openid-configuration` to it, so an issuer of `https://sso.county.example/schools` is fetched at `https://sso.county.example/schools/.well-known/openid-configuration` — the issuer's own path component stays, and the well-known segment goes after it. That is deliberate: appending rather than inserting lets one host carry several independent issuers. The response is a JSON object served as `application/json`. From it a relying party reads `issuer`, `authorization_endpoint`, `token_endpoint`, `userinfo_endpoint`, `jwks_uri` and `registration_endpoint`, plus the `*_supported` capability members. It is still configured with its own `client_id` and redirect URI; discovery supplies the provider's side.

code

http · 6 lines
http
GET /schools/.well-known/openid-configuration HTTP/1.1
Host: sso.county.example
Accept: application/json

HTTP/1.1 200 OK
Content-Type: application/json

go deeper

for a junior

Recall the shape: one issuer URL in configuration, and /.well-known/openid-configuration concatenated to it at runtime. Be able to name what comes back - the endpoint URLs and the jwks_uri.

for a middle

Explain why the rule is concatenation and not insertion: several issuers can share one host, each with its own document under its own path. Separate the required members from the merely recommended ones.

for a senior

Show that you validate the document rather than trusting it. Say what you do when a recommended member is missing, and how a browser-based client's cross-origin constraint changes which providers actually work.

for a principal

Frame it as a runtime contract with an external party: your deployment configuration shrinks to one value per tenant, and in exchange your availability now depends on a document you fetch from someone else's host.

## The problem discovery solves A relying party — the application a user signs in to — needs several absolute URLs before an OpenID Connect flow can start: where to send the browser, where to exchange an authorization code, where to read profile claims, and where the provider publishes the key set its signatures are verified against. Hardcoding those is how an integration rots. A provider moves an endpoint, or a second provider is added, and the deployment configuration grows half a dozen entries per tenant that nobody dares change. OpenID Connect Discovery collapses them into **one** configured value — the **Issuer Identifier** — plus one fetch at runtime. A booking system for a school's parents' evening that accepts sign-in from the local authority running the accounts is handed exactly that and nothing else: an issuer URL. ## Building the request URL The Issuer Identifier is a URL using the `https` scheme, carrying no query component and no fragment component. The configuration document's URL is formed by **concatenating** `/.well-known/openid-configuration` to the Issuer Identifier, with any terminating `/` removed first. | Issuer Identifier | Configuration document URL | |---|---| | `https://sso.county.example` | `https://sso.county.example/.well-known/openid-configuration` | | `https://sso.county.example/` | `https://sso.county.example/.well-known/openid-configuration` | | `https://sso.county.example/schools` | `https://sso.county.example/schools/.well-known/openid-configuration` | The third row is the one candidates get wrong. The issuer's path component is **kept**, and the well-known segment goes **after** it. The specification gives the reason plainly: appending rather than inserting is what lets a single host publish several independent issuers, each with its own document, without them colliding at the host root. The well-known URI space itself is the one registered by `RFC 5785`. It is worth holding that shape in mind because the neighbouring OAuth authorization-server metadata document defined by `RFC 8414` is built the other way round — its well-known string is **inserted** between the host and the issuer's path, giving a URL under `/.well-known/oauth-authorization-server`. Same deployment, two documents, two differently-shaped URLs. ## What comes back A `200` response whose body is a JSON object, served with the media type `application/json`. JSON here is `RFC 8259` JSON — no wrapper, no signature envelope, no XML. The endpoint SHOULD also support cross-origin requests, because a client running in a browser has to be able to read it directly. The specification separates what a conforming document **MUST** carry from what it merely **SHOULD**: - **REQUIRED**: `issuer`, `authorization_endpoint`, `jwks_uri`, `response_types_supported`, `subject_types_supported`, `id_token_signing_alg_values_supported`. `token_endpoint` is required too for any provider that issues an authorization code to be exchanged. - **RECOMMENDED**: `userinfo_endpoint`, `registration_endpoint`, `scopes_supported`, `claims_supported`. - **OPTIONAL**: the long tail of `*_supported` capability members — `grant_types_supported`, `token_endpoint_auth_methods_supported`, `claims_parameter_supported`, `request_parameter_supported`, `request_uri_parameter_supported`, `display_values_supported`, `ui_locales_supported`, `claims_locales_supported` and the rest. ## The members a relying party bootstraps from 1. `issuer` — the provider's own name for itself. It is not decoration: it exists to be compared against the URL you used to build the request and against the `iss` claim of ID tokens later. 2. `authorization_endpoint` — where the browser is sent to start the flow. 3. `token_endpoint` — where the code is exchanged, server to server. 4. `userinfo_endpoint` — where claims about the signed-in user can be read. 5. `jwks_uri` — the URL at which the provider publishes its key set. Discovery's job ends at **advertising** that URL; what a verifier then does with the keys belongs to token validation, not to the configuration document. 6. `registration_endpoint` — where a client may register itself, when the provider allows it. ## Three things this is not - **Not resolving which provider a user belongs to.** Discovery here means fetching a known provider's configuration. Working out which provider a given person should be sent to is a different job with a different mechanism. - **Not the OAuth authorization-server metadata document.** Different well-known string, opposite construction rule. - **Not a substitute for checking what came back.** Fetching over `https` tells you the connection was to the host you named; it does not by itself tell you the JSON describes the issuer you meant. That comparison is a step of its own. The practical payoff is the one a first-screen interviewer is listening for: one value in configuration, everything else read at runtime from a document the provider controls.

  • The issuer URL you were given ends in a slash. What exactly do you request?
    Remove the terminating `/` first, then concatenate. An issuer of `https://sso.county.example/` is fetched at `https://sso.county.example/.well-known/openid-configuration`, with a single slash before the well-known segment. Keeping the trailing slash and appending would produce a doubled slash and a different URL, and the `issuer` member you compare against afterwards is the form without it.
  • Which members must a conforming OpenID Provider configuration document carry, and which are only recommended?
    REQUIRED: `issuer`, `authorization_endpoint`, `jwks_uri`, `response_types_supported`, `subject_types_supported` and `id_token_signing_alg_values_supported`, plus `token_endpoint` for any provider issuing a code to exchange. RECOMMENDED, and therefore legitimately absent: `userinfo_endpoint`, `registration_endpoint`, `scopes_supported` and `claims_supported`. Treating a recommended member's absence as a broken provider is a common misreading.
  • What media type must the response carry, and why does a client running in a browser care?
    The document is returned as `application/json`. A browser-based relying party has an additional constraint: the fetch is cross-origin, so the specification says the endpoint SHOULD support cross-origin requests. A provider that omits the relevant response headers is readable from a server but not from page script, which is why the same issuer can work for one client shape and not another.

A building with several tenants puts a noticeboard just inside each tenant's own door rather than one board at the street entrance. That is why the well-known segment goes after the issuer's path: one host, many issuers, no collision.

saying these in an interview costs you the question

  • Thinks the well-known segment replaces the issuer's own path component
  • Assumes every provider publishes the document at the host root
  • Confuses it with the RFC 8414 authorization-server metadata path
  • Expects an HTML page or a redirect rather than application/json
  • Thinks discovery means working out which provider a user belongs to
  • Keeps the issuer's trailing slash and requests a doubled-slash URL
open as a page

In OpenID Connect, what does `response_type=code` ask a provider to return to the client's redirect URI?

level: juniorimportance: must knowfreq 72%

basics

~20 s

A single short-lived authorization code, and nothing else. With response_type=code the provider puts no ID token and no access token on the redirect; the client exchanges the code at the token endpoint and receives both there.

open as a page

Which OpenID Connect request parameters ask a provider for a stronger or a fresher sign-in, and how do they differ?

level: middleimportance: must knowfreq 58%

basics

~20 s

acr_values names the authentication context class references the request prefers, in order of preference; max_age caps how many seconds may have passed since the user last actively authenticated. Strength versus recency — and only max_age carries an obligation on the provider.

open as a page

Which `response_type` should a browser-only client and a server-side client each ask for, and what differs downstream?

level: middleimportance: must knowfreq 64%

basics

~20 s

Both ask for response_type=code. The response type is the same because neither wants identity artefacts delivered through the browser; what differs is the token-endpoint leg, where the server-side client can authenticate itself and the browser-only client cannot.

open as a page

What does a relying party send to an OpenID Provider's `end_session_endpoint` to sign a user out, and what does each parameter do?

level: middleimportance: must knowfreq 58%

basics

~10 s

The relying party redirects the browser to end_session_endpoint carrying id_token_hint (which session to end), client_id, a pre-registered post_logout_redirect_uri, state and ui_locales. The provider ends its own session, then redirects back.

open as a page

When an OpenID Provider notifies relying parties through `frontchannel_logout_uri`, why does the chain clear only some sessions?

level: seniorimportance: must knowfreq 52%

basics

~20 s

Front-channel logout renders one hidden frame per relying party on the provider's logout page. Every frame must load and finish in that browser before the user leaves, nothing is acknowledged, and nothing retries, so any frame that fails is a session left open.

open as a page

In OpenID Connect, which authentication-request parameter makes a provider re-prompt a user who already has a session there?

level: juniorimportance: should knowfreq 40%

basics

~20 s

prompt=login on the authentication request asks the provider to re-authenticate the user even though a provider session already exists. Without it, a provider may answer from that session silently, so the browser bounces out and back with no sign-in shown.

open as a page

What does an OpenID Connect authentication request with `prompt=none` ask for, and what comes back when it cannot be satisfied?

level: middleimportance: should knowfreq 44%

basics

~10 s

prompt=none forbids the provider from displaying any authentication or consent interface: answer from an existing session or return an error. The usual errors are login_required, interaction_required, consent_required and account_selection_required, delivered to the redirect URI.

open as a page

What must the issuer member of a fetched OpenID Provider configuration document match, and why does that comparison matter?

level: middleimportance: should knowfreq 46%

basics

~20 s

The issuer member returned must be identical to the Issuer URL used as the prefix to fetch the document, and identical to the iss claim in ID tokens from that provider. Those three comparisons are what tie a fetched JSON blob to a named issuer.

open as a page

Using `session_state` and `check_session_iframe`, how does a relying party notice that the provider session has ended?

level: middleimportance: should knowfreq 40%

basics

~20 s

The provider returns session_state with the authentication response and publishes check_session_iframe. The relying party loads that frame hidden and polls it by postMessage, comparing digests; a reported change is a prompt to re-check, never a logout instruction.

open as a page

RFC 9470 lets an API refuse a call whose access token reflects too weak a sign-in: what does the resource server return, and what does the client do next?

level: seniorimportance: should knowfreq 35%

basics

~20 s

The resource server answers 401 Unauthorized with WWW-Authenticate: Bearer error="insufficient_user_authentication", optionally carrying acr_values and max_age to state what it needs. The client then starts a new authorization request with those values, and the provider re-authenticates.

open as a page

A relying party works against one provider but fails against another — which OpenID Provider configuration document members should it have checked?

level: seniorimportance: should knowfreq 38%

basics

~10 s

The *_supported members. They are capability negotiation, not documentation: scopes_supported, response_types_supported, grant_types_supported, token_endpoint_auth_methods_supported and the booleans such as request_parameter_supported tell a client what this provider will accept before a user ever reaches it.

open as a page

Which `response_type` delivery property matters when a sign-in lands in a browser on a screen a whole crew room can read?

level: seniorimportance: should knowfreq 44%

basics

~20 s

Whether the response type returns identity artefacts from the authorization endpoint. Any value carrying id_token or an access token there delivers it inside the redirect URI, on a display several people can read; response_type=code leaves only a single-use handle on that channel.

open as a page

With `response_type=code id_token`, what arrives on the redirect, and what does the ID token's `c_hash` bind it to?

level: seniorimportance: should knowfreq 38%

basics

~20 s

A code and an id_token arrive together on the redirect, which is the Hybrid Flow. Because both travelled the front channel, the id_token must carry c_hash, a value derived from that code, so the client can prove the two belong to one response.

open as a page

What does the `logout_token` in a back-channel logout POST carry, and why can that notification never sign the browser out?

level: seniorimportance: should knowfreq 46%

basics

~20 s

The provider POSTs a signed logout_token to the relying party's backchannel_logout_uri, carrying iss, aud, iat, jti, an events claim naming the back-channel logout event, and sub or sid. It travels server to server, so nothing in the browser is touched.

open as a page

In an OpenID Connect estate whose relying parties do not all support back-channel logout notification, how would you define and deliver 'signed out everywhere'?

level: principalimportance: should knowfreq 28%

basics

~20 s

Define the promise in tiers: ending the provider session is the only guaranteed part, notification to relying parties is best effort through both channels, and for relying parties that support neither, session lifetime is the only remaining control.

open as a page