A client has fetched an RFC 8414 metadata document — what must it verify before using any endpoint URL inside it?
answer
- compare what came back
- identical, not merely equivalent
- simple string comparison, character for character
- against the identifier the URL was built from
- a mismatch discards the whole document
basics
~20 sThe issuer member returned in the document must be identical, by simple string comparison, to the issuer identifier the client used to build the fetch URL. RFC 8414 says that if the values differ, the data in the response must not be used.
solid answer
~50 sRFC 8414 names one validation step and it is a comparison: the `issuer` value in the document **must be identical** to the issuer identifier into which the well-known string was inserted to build the URL that was fetched. Not equivalent after normalisation — identical, character for character. If they differ, the response must not be used, and that means the whole document, not just the `issuer` member. The retrieval itself runs over https with the server's certificate validated, so the transport says which host answered; the issuer comparison is what says the answer belongs to the authorization server the client was configured to talk to. Note that RFC 8414 does not require the advertised endpoints to sit on the issuer's host, which is why inspecting hostnames is not a substitute for the comparison. Where the document may travel a path the client does not fully control, `signed_metadata` carries the same claims as a signed JWT.
code
json · 6 lines{
"issuer": "https://id.example.org/contest/",
"authorization_endpoint": "https://id.example.org/contest/authorize",
"token_endpoint": "https://id.example.org/contest/token",
"response_types_supported": ["code"]
}go deeper
Recall that the document states its own issuer, and that this value has to be compared with the issuer the client was configured with before anything in the document is used.
Explain why the comparison is character for character rather than a normalised URL match, and name the near-misses — trailing slash, explicit port, case, scheme — that must fail it.
Show the operating story: what the failure actually looks like in production, why a mismatch must discard the whole document rather than one member, and what you log so an operator can tell which of the two values is wrong.
Frame it as where trust enters the system — a single configured identifier — and decide what else you pin, whether you require signed metadata from partners, and what you accept when you consume a document you do not control.
## The check the specification names RFC 8414 gives the client exactly one validation rule for the document it just fetched: the **`issuer` value returned must be identical to the issuer identifier into which the well-known URI string was inserted** to create the URL the document came from. If the two are not identical, the data in the response **must not be used**. Two details in that sentence do the work. First, *identical* — a simple string comparison, not a URL equivalence test. Second, *must not be used* applies to the **whole response**, not merely to the mismatching member: the client does not get to keep the endpoints and shrug at the name. ## Identical means identical Every one of these is a mismatch, and each shows up in real deployments: | the configured issuer | the value returned | identical? | |---|---|---| | `https://id.example.org/contest` | `https://id.example.org/contest/` | no — a trailing slash is a character | | `https://id.example.org/contest` | `https://ID.example.org/contest` | no — the comparison is not case-folded | | `https://id.example.org/contest` | `http://id.example.org/contest` | no — and an issuer must be https anyway | | `https://id.example.org/contest` | `https://id.example.org:443/contest` | no — an explicit default port still differs | The temptation is to normalise before comparing, and it is the wrong instinct. The moment a client canonicalises, two issuer identifiers that the specification treats as distinct start being treated as one, and the value the client stores stops being the value the server publishes. Keep the configured string byte-exact from configuration, through URL construction, into the comparison. ## What the match establishes, and what it does not It establishes that the document in hand is **the one published for the issuer identifier the client was configured with**. That is a narrow and useful statement. It does not establish any of the following: - that the advertised endpoints are operated by the same party as the issuer's host — RFC 8414 does not require the endpoints to share the issuer's host, and a legitimate deployment may point `token_endpoint` elsewhere; - that the server is trustworthy in any general sense, only that this is the document belonging to the name you were given; - anything at all about a **later** message. This is a check on a document read at bootstrap; what a client does with responses it receives afterwards is a separate mechanism with separate rules; - that the configured issuer was the right one to begin with. Garbage in the configuration produces a perfectly matching document for the wrong authorization server. The last point is worth saying out loud, because it is where the check earns its keep operationally: the failure it prevents is almost never exotic. It is a tenant's issuer copied between a test and a live environment; a cache keyed on the metadata URL rather than on the issuer, so two tenants share an entry; a server whose operators changed the issuer identifier and left a redirect in place. In every one of those cases the fetch succeeds, the JSON parses, the endpoints look plausible, and the comparison is the only thing that says no. ## When the transport is not enough The retrieval runs over https and the server's certificate is validated, so a client knows which host answered. Where the document may pass through a path the client does not fully control, or where it is distributed rather than fetched live, RFC 8414 offers **`signed_metadata`**: a JWT containing the metadata values as claims, signed with JWS and carrying the issuer identifier in its `iss` claim. A client that verifies it takes the signed claims **in preference to** the corresponding plain JSON members. It is optional, and most deployments do not publish it, so a client should handle both shapes. ## The order to do it in 1. Derive the metadata URL from the configured issuer identifier. 2. Fetch it over https, validating the certificate for that host; treat any non-success status as a failure to discover, not as an empty document. 3. Parse the JSON body. 4. If `signed_metadata` is present and the client is configured to verify it, verify the JWS and use those claims in place of the corresponding plain members. 5. Compare the resulting `issuer` with the configured identifier, character for character. On a mismatch, discard the document and fail loudly, naming both values in the log so the operator can see which one is wrong. 6. Only then read `authorization_endpoint`, `token_endpoint`, `jwks_uri` and the capability fields. Step 5 before step 6 is the entire question. A client that reads the endpoints first and validates afterwards has already made the decision the check exists to inform.
- Name differences between two issuer strings that a human would call the same server but the check must reject.A trailing slash on one and not the other; an explicit `:443` where the other omits it; a case difference anywhere in the string; `http` where the other has `https`; a percent-encoded character on one side only. The comparison is character for character, so each of these fails and the document is discarded.
- Must the endpoints advertised in the document live on the issuer's host?No. RFC 8414 does not require it, and legitimate deployments do split them. That is precisely why the specification names a comparison against the configured issuer identifier rather than any kind of hostname inspection — checking that the endpoints "look right" is not the check.
- What is `signed_metadata` for, and how does a client treat it?It is a JWT carrying the metadata values as claims, signed with JWS and containing the issuer identifier in its `iss` claim, for a document that may travel a path the client does not fully control. A client that verifies it prefers those claims over the corresponding plain JSON members. It is optional, so a client must also handle a document without it.
A metadata document that names its own issuer is like a sealed envelope that states the sender inside: it is only worth anything if you compare that name against the correspondent you actually wrote to, rather than against the postmark on the outside.
saying these in an interview costs you the question
- Checks only that the fetch succeeded and the JSON parsed.
- Compares the issuer against the host the document was fetched from.
- Treats a trailing-slash difference as an acceptable match.
- Believes a valid TLS connection removes the need for the issuer check.
- Thinks signed_metadata must be present on every metadata document.
- Keeps the endpoints and ignores a mismatching issuer value.