feat(auth): support both insert and append metadata discovery (#4310)#4346
Open
reinkrul wants to merge 3 commits into
Open
feat(auth): support both insert and append metadata discovery (#4310)#4346reinkrul wants to merge 3 commits into
reinkrul wants to merge 3 commits into
Conversation
Metadata discovery derived URLs using only the RFC 8414 insert convention (well-known segment at the authority root, issuer/AS path appended). Servers that publish metadata only under the OIDC Discovery append convention (well-known after the path) returned 404 and could not complete issuance or token flows without per-deployment nginx rewrites. Discovery now tries candidate locations in priority order and takes the first matching document: 1. insert (RFC 8414, unchanged happy path) 2. append (OIDC Discovery) 3. append openid-configuration (AS metadata only) When the identifier has no path both forms collapse to one URL, so spec-compliant servers still make a single request. Each candidate shares the identifier's host and is SSRF-validated via core.ParsePublicURL, and the existing identifier-match check (credential_issuer / issuer must equal the requested identifier) is enforced on the accepted document, so the fallback cannot be steered to an attacker-chosen file. On exhaustion the error names the identifier and reports only non-404 failures; a >= 500 failure still maps to 502 Bad Gateway. Assisted by AI (cherry picked from commit f01c39a0827a90dbba95530169123a367c74006a)
Some authorization servers (e.g. IdentityServer) normalize the metadata issuer with a trailing slash, so a server reached at the append location with issuer "https://host/oauth/" was rejected against the requested identifier "https://host/oauth". Discovery then fell back to the credential issuer and surfaced an unrelated 404. Compare issuer / credential_issuer with a trailing-slash tolerance via oauth.IdentifiersMatch. Still rejects genuinely different identifiers, so the fallback cannot be steered to another document. Assisted by AI (cherry picked from commit b416b3d)
Contributor
|
Coverage Impact ⬆️ Merging this pull request will increase total coverage on Modified Files with Diff Coverage (5)
🤖 Increase coverage with AI coding...🚦 See full report on Qlty Cloud » 🛟 Help
|
…iscovery Replace the duplicated well-known metadata fetch-loops in iam/client.go and openid4vci/client.go with a single generic oauth.FetchMetadata[T]. Each metadata type provides its own well-known path via WellKnownPath() and its issuer via GetIssuer(); the helper derives the candidate URLs (insert + append placements), fetches the first match, validates the issuer, and lists the tried locations on failure. IdentifiersMatch is now package-internal. The signed-JWT OpenIDConfiguration keeps its own implementation. Assisted by AI
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Closes #4310
Problem
Metadata discovery derived URLs using only the RFC 8414 insert convention (well-known segment at the authority root, issuer/AS path appended:
https://host/.well-known/<doc>/<path>). Servers that publish metadata only under the OIDC Discovery append convention (https://host/<path>/.well-known/<doc>) returned 404/401/403/405, so issuance and token flows could not complete without per-deployment nginx rewrite rules.Affected:
openid-credential-issuer) —auth/openid4vcioauth-authorization-server) —auth/client/iamChange
Discovery tries both placements in priority order and takes the first matching document:
When the identifier has no path the two collapse to one URL, so spec-compliant servers still make a single request — no added latency on the happy path.
Implemented by consolidating the previously-duplicated per-type fetch loops into one generic helper
oauth.FetchMetadata[T]:WellKnownPath()and its issuer viaGetIssuer(); the helper derives the candidate URLs (preserving the%2F/RawPathhandling), fetches the first that returns 200 and JSON-decodes, and validates the issuer match./).core.ParsePublicURL; the identifier-match check (issuer/credential_issuermust equal the requested identifier) is enforced on the accepted document, so the fallback cannot be steered to an attacker-chosen file.>= 500failure maps to502 Bad Gateway.IdentifiersMatchis now package-internal. The signed-JWTOpenIDConfigurationkeeps its own (master) implementation.Compatibility
Fully additive. Insert-convention servers behave identically with a single request. No new config keys; operators can remove per-deployment nginx metadata-rewrite rules.
Note: the iam path now enforces the
issueridentifier-match check on the accepted AS metadata document (previously absent). Nuts-served metadata sets this correctly, but a partner whose metadataissuerfield does not equal the requested identifier (modulo trailing slash) would now be rejected rather than silently accepted.Tests
auth/oauth:FetchMetadata— insert single-request, append fallback, identifier-mismatch-falls-through, trailing-slash match, all-404 not-found (names the tried locations), non-404 preserved, upstream 5xx surfaced ascore.HttpError, invalid JSON, invalid identifier; pluswellKnownCandidatesordering andIssuerIdToWellKnown.auth/openid4vci: insert-only, append-only, both-404, identifier-mismatch-falls-through, non-404 preserved.auth/client/iam: same matrix plus the>= 500→502mapping.Assisted by AI