Skip to content

feat: exact redirect_uri matching via --redirect-uris - #786

Merged
lakhansamani merged 1 commit into
mainfrom
fix/exact-redirect-uri-matching
Aug 19, 2026
Merged

feat: exact redirect_uri matching via --redirect-uris#786
lakhansamani merged 1 commit into
mainfrom
fix/exact-redirect-uri-matching

Conversation

@lakhansamani

Copy link
Copy Markdown
Contributor

Closes the OIDC Core §3.1.2.1 gap the conformance run found.

The gap

A client that registered its redirect URIs — through RFC 7591 registration or a metadata document — has always been held to an exact match. The deployment's own client (named by --client-id) could not be: it is seeded into the registry at boot and nothing writes RedirectURIs to that row, so checkClientRedirectURI always fell through to IsValidRedirectURI(uri, AllowedOrigins, host), which compares origins.

Probed against 2.4.0:

redirect_uri=https://<allowed-origin>/totally/unregistered/path  -> 302 + code
redirect_uri=https://evil.example.com/cb                         -> 400

The OpenID Foundation Basic profile fails oidcc-ensure-registered-redirect-uri and oidcc-ensure-request-object-with-redirect-uri on exactly this.

The fix

--redirect-uris, a comma-separated list of exact URIs for that client. When set, the same comparison registered clients already get applies — including the RFC 8252 §7.3 loopback-port carve-out. When unset, nothing changes.

Read from config rather than written to the registry row: persisting it would need UpdateClient to carry the field across every storage backend, and would leave a stale allow-list behind the day an operator removes the flag.

Not the default. Exact matching as the default would refuse the callback of every deployment that never listed its URIs.

Verified

  • make test 44 pkgs, make lint 0 issues, make smoke — all pass
  • New unit tests: the origin fallback when unset, exact matching when set, and that the list does not leak onto another client
  • Boot validation refuses entries that could never match (no scheme, fragment, user info)
  • Live probe on a build with the flag set: registered → 302, unregistered path on the same origin → 400

A client that registered its redirect URIs - through RFC 7591 or a
metadata document - has always been held to an exact match. The
deployment's own client could not be: it is seeded into the registry at
boot and nothing writes RedirectURIs to that row, so it always fell
through to the --allowed-origins check, which compares ORIGINS. Every
path under an allowed origin was a valid redirect target. OIDC Core
3.1.2.1 and RFC 6749 3.1.2.3 both require an exact match; the OpenID
Foundation suite fails oidcc-ensure-registered-redirect-uri and
oidcc-ensure-request-object-with-redirect-uri on the origin behaviour.

Read from config rather than the registry row on purpose: writing it at
boot would need UpdateClient to carry the field across every storage
backend, and would leave a stale allow-list behind the day an operator
removes the flag. The flag is then the whole state.

Unset keeps the origin fallback. Making exact matching the default would
refuse the callback of every deployment that never listed its URIs.

Entries that could never match - no scheme, a fragment, user info - are
refused at startup rather than at every login, where the flag would look
configured and nothing would name the entry at fault.
@lakhansamani
lakhansamani merged commit 4ad0758 into main Aug 19, 2026
4 checks passed
@lakhansamani
lakhansamani deleted the fix/exact-redirect-uri-matching branch August 19, 2026 08:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant