A relying party works against one provider but fails against another — which OpenID Provider configuration document members should it have checked?
answer
- the long tail ending in _supported
- capability negotiation nobody actually negotiates
- absent is a default, not a no
- request_uri_parameter_supported defaults to true
- check at load, not at first login
basics
~10 sThe *_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.
solid answer
~40 sAn integration built against one provider quietly encodes that provider's capabilities. The second provider advertises a different set, and the mismatch surfaces as a failure at the authorization endpoint during someone's first login rather than at deployment. The fix is to read the `*_supported` members at configuration load and fail loudly. Check `scopes_supported`, `response_types_supported`, `grant_types_supported` and especially `token_endpoint_auth_methods_supported`, which decides how your client authenticates at all. Two subtleties bite: an **omitted** member is not automatically a no — the specification supplies defaults, and `request_uri_parameter_supported` defaults to **true** while `request_parameter_supported` and `claims_parameter_supported` default to **false**. And an advertised list describes the **provider**, not your registration: a value in `scopes_supported` can still be refused for your `client_id`.
code
json · 9 lines{
"issuer": "https://sso.borough.example",
"scopes_supported": ["openid", "profile", "email"],
"response_types_supported": ["code"],
"grant_types_supported": ["authorization_code"],
"token_endpoint_auth_methods_supported": ["private_key_jwt"],
"subject_types_supported": ["pairwise"],
"claims_parameter_supported": false
}go deeper
Recall that the document carries more than endpoint addresses: a set of members ending in _supported describing what the provider accepts. Know they exist and are worth reading.
Explain what a mismatch in a specific member costs, and be able to say which members are required in a conformant document and which are only recommended.
Show the operational instinct: validate capabilities at configuration load and fail with the member named, rather than letting the mismatch surface as an unreproducible login failure against a provider you do not operate.
Frame the real exposure: onboarding a partner identity provider is a compatibility negotiation you cannot enforce, so decide which capabilities are contractual prerequisites and which your product will adapt to.
## Capability negotiation nobody negotiates Most of an OpenID Provider configuration document is not addresses. It is a long tail of members ending in `_supported`, and they exist so a relying party can find out what a provider will accept **before** sending a user at it. In practice almost nobody reads them, because the first integration works: the code was written while looking at one provider's behaviour, and that provider's capabilities are baked into it silently. The parents' evening booking system meets this the day a second local authority is onboarded. Everything is configured, the issuer resolves, the document fetches — and the first parent to click sign in gets an error page from a provider that will not honour something the client assumed. ## The members worth checking at load time | Member | What a mismatch costs | |---|---| | `scopes_supported` | A requested scope value the provider does not offer | | `response_types_supported` | The client asks for a `response_type` the provider will not issue | | `grant_types_supported` | The exchange the client intends to perform is not offered | | `token_endpoint_auth_methods_supported` | The client cannot authenticate at the token endpoint at all | | `id_token_signing_alg_values_supported` | Nothing in the list is something the client can verify | | `claims_parameter_supported` | A `claims` request parameter is silently ignored | | `request_parameter_supported` | A request-object parameter is rejected or ignored | | `acr_values_supported` | An `acr_values` request the provider cannot satisfy | | `subject_types_supported`, `claim_types_supported` | The identifier or claim shape the client stores differs | | `display_values_supported`, `ui_locales_supported`, `claims_locales_supported` | Presentation hints quietly dropped | The one that most often breaks an onboarding outright is `token_endpoint_auth_methods_supported`. Client authentication is not optional plumbing; if the provider does not offer the method the client was built for, there is no exchange at all, and the failure appears at the token endpoint with a generic error long after the user has already authenticated. ## Absence is not a no This is the subtlety that catches experienced people. Several of the boolean members carry a **specified default** when omitted, and the defaults are not uniform: - `request_uri_parameter_supported` — omitted means **true**. - `request_parameter_supported` — omitted means **false**. - `claims_parameter_supported` — omitted means **false**. So a client that reads a missing member as "unsupported" is wrong about the first, and a client that reads a missing member as "probably fine" is wrong about the other two. The only correct reading is: when the member is absent, apply the default the specification states for that member. The same discipline applies to the REQUIRED and RECOMMENDED split. `issuer`, `authorization_endpoint`, `jwks_uri`, `response_types_supported`, `subject_types_supported` and `id_token_signing_alg_values_supported` are REQUIRED — a document missing one is not conformant and that is worth saying out loud in a log. `scopes_supported`, `claims_supported`, `userinfo_endpoint` and `registration_endpoint` are only RECOMMENDED, so their absence is legitimate and must not be treated as a provider fault. ## An advertised list is about the provider, not about you The second trap is reading a capability list as a promise. `scopes_supported` says what this provider is willing to offer **to some client**. It does not say what your `client_id` is registered for. A scope value can be listed and still refused for your registration, and a provider can also honour something it never advertised, since several of these members are OPTIONAL and providers under-declare. That means the capability check is a **fast-fail filter, not a guarantee**: 1. At configuration load, fetch the document once and compare the client's requirements against it. 2. Fail startup, naming the exact member and the exact value that is missing, for anything the client genuinely cannot work without. 3. Warn rather than fail for anything advertised as merely absent from a RECOMMENDED list. 4. Still handle a runtime rejection gracefully, because registration-level refusals never appear in the document. ## Why the timing is the real answer The technical content here is modest — read some JSON members. The seniority is entirely in **when** you read them. A capability mismatch discovered at configuration load is a deployment that does not start, with a log line naming the member. The same mismatch discovered lazily is a parent standing at a login screen at eight in the evening with a correlation identifier nobody can resolve, because the failing component is a provider you do not operate. Moving the check earlier converts an unreproducible support ticket into a startup failure, and that trade is what an interviewer is listening for.
- A provider's document omits claims_parameter_supported entirely. What may the client assume?That it is false, because the specification states that default for that member. The reverse reading is what makes this worth asking: `request_uri_parameter_supported` omitted means true. Absence therefore carries a per-member meaning, and treating every missing boolean the same way is wrong for one of these two whichever way you guess.
- A scope value is listed in scopes_supported but the authorization request is refused. Is the provider non-conformant?No. The list describes what the provider offers in general; it is not a statement about your registration. A scope can be advertised and still not granted to your `client_id`. Capability checks are a fast-fail filter against obvious mismatches, not a guarantee, so runtime refusals still need handling.
- Which single capability member most often stops a second provider working at all, and why?`token_endpoint_auth_methods_supported`. If the provider does not offer the client-authentication method the integration was built around, the code exchange cannot happen, so the failure lands after the user has already authenticated and looks like a broken application rather than a configuration mismatch.
- Should a missing userinfo_endpoint fail your startup?Not by itself — it is RECOMMENDED, not REQUIRED, so its absence is a conformant provider making a choice. It should fail startup only if your application genuinely depends on reading claims from that endpoint. A missing REQUIRED member such as `jwks_uri` is a different matter and should be reported as a non-conformant document.
A supplier's catalogue lists what the factory can make. It is not your contract, so a line in the catalogue can still be refused against your account, and the catalogue is worth reading before you promise a delivery date.
saying these in an interview costs you the question
- Assumes any value listed in scopes_supported is available to its own client_id
- Reads every omitted boolean member as meaning unsupported
- Treats a missing RECOMMENDED member as a broken provider
- Discovers capability mismatches at a user's first login
- Hardcodes the first provider's capabilities into the client
- Believes an advertised list is a promise rather than a filter