Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat: support multiple OIDC redirect URIs - #25408

Merged
ibetitsmike merged 6 commits into
coder:mainfrom
ibdafna:feat/oidc-redirect-allowed-hosts
Jul 5, 2026
Merged

feat: support multiple OIDC redirect URIs#25408
ibetitsmike merged 6 commits into
coder:mainfrom
ibdafna:feat/oidc-redirect-allowed-hosts

Conversation

@ibdafna

@ibdafna ibdafna commented May 15, 2026

Copy link
Copy Markdown
Contributor

This PR adds a new opt-in setting, CODER_OIDC_REDIRECT_ALLOWED_HOSTS, that lets a single Coder deployment complete OIDC login on more than one hostname. When the allowlist is non-empty, Coder picks the OIDC redirect_uri based on the incoming request's Host header (validated against the list) instead of always using the static URL derived from CODER_ACCESS_URL. When unset, the (default) behavior is identical to today.

The motivation is that a single Coder deployment is frequently reachable via multiple hostnames - for example, an internal hostname for users on a corporate VPN and a different hostname routed through a zero-trust gateway for users off-VPN - but OIDC login today only works on whichever single hostname CODER_ACCESS_URL points to, because the redirect_uri sent to the IdP is fixed at server startup. Users who reach the deployment on any other valid hostname can see the login page but fail the OIDC callback, since the IdP redirects them back to a hostname they can't reach (or whose cookies they don't have).

@github-actions github-actions Bot added the community Pull Requests and issues created by the community. label May 15, 2026
@ibdafna
ibdafna force-pushed the feat/oidc-redirect-allowed-hosts branch 3 times, most recently from 55a526d to 4817327 Compare May 16, 2026 05:57
@ibdafna
ibdafna marked this pull request as ready for review May 18, 2026 16:15
@github-actions github-actions Bot added the stale This issue is like stale bread. label May 30, 2026
@github-actions github-actions Bot closed this Jun 2, 2026
@ibetitsmike ibetitsmike reopened this Jun 2, 2026
@ibetitsmike ibetitsmike removed the stale This issue is like stale bread. label Jun 2, 2026
@deansheather deansheather changed the title Support multiple OIDC redirect URIs feat: support multiple OIDC redirect URIs Jun 3, 2026
Comment thread coderd/httpmw/oauth2.go Outdated
Comment thread coderd/httpmw/oauth2.go Outdated
@github-actions github-actions Bot added the stale This issue is like stale bread. label Jun 11, 2026
@github-actions github-actions Bot closed this Jun 15, 2026
@Shelnutt2 Shelnutt2 removed the stale This issue is like stale bread. label Jun 22, 2026
@Shelnutt2 Shelnutt2 reopened this Jun 22, 2026
@ibdafna
ibdafna force-pushed the feat/oidc-redirect-allowed-hosts branch from 0679b40 to 349b505 Compare June 22, 2026 21:59
Comment thread coderd/httpmw/oauth2.go Outdated
Comment thread coderd/httpmw/oauth2.go Outdated
Comment thread coderd/httpmw/oauth2.go
Comment thread coderd/httpmw/oauth2.go
Comment thread coderd/httpmw/oauth2.go Outdated
Comment thread coderd/httpmw/oauth2_test.go
@zedkipp

zedkipp commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Looks good from a functionality standpoint. There's some lint/fmt issues, and code-gen needs to be run (see make gen).

@ibdafna

ibdafna commented Jun 24, 2026

Copy link
Copy Markdown
Contributor Author

Looks good from a functionality standpoint. There's some lint/fmt issues, and code-gen needs to be run (see make gen).

@zedkipp should be done now.

@zedkipp

zedkipp commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Formatting checks are still failing. Try make fmt, which should resolve the docs formatting issues I see flagged by some of the checks.

@ibdafna

ibdafna commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

Formatting checks are still failing. Try make fmt, which should resolve the docs formatting issues I see flagged by some of the checks.

@zedkipp fmt passes now, but I'm not sure about the rest.

@ibdafna

ibdafna commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

@zedkipp I don't merge permissions here. Could someone help me with this? Looks like we'll need a rebase now

@ibdafna
ibdafna force-pushed the feat/oidc-redirect-allowed-hosts branch from 99b6c00 to ddac0d2 Compare June 26, 2026 18:21
@zedkipp
zedkipp enabled auto-merge (squash) June 26, 2026 19:30
ibdafna added 5 commits June 27, 2026 09:07
… dynamic redirect_uri

Some upstream reverse proxies set X-Forwarded-Proto to the inner-hop
scheme (the proxy-to-coderd leg, often http) rather than the original
client-facing scheme. Trusting that header in the dynamic-host code path
produced redirect_uri values the IdP rejected.

Thread the configured AccessURL scheme into the middleware as
RedirectDefaultScheme and prefer it over r.TLS / X-Forwarded-Proto.
This matches what the static OIDC path uses today (vals.AccessURL.Scheme)
and makes the dynamic path consistent. Request-derived detection remains
as the fallback for deployments without a configured AccessURL.
Address review feedback from coder#25408:

* The four-case switch had three dead branches in practice: the only
  real caller (cli/server.go) always passes a non-empty defaultScheme.
  Cases that fell back to r.TLS, X-Forwarded-Proto, or a literal "http"
  string were unreachable in any production code path. Worse, the bare
  "http" default would have produced silently insecure redirect_uris
  in the unlikely event the function was ever called without a
  defaultScheme; the IdP would reject the request and the failure mode
  would be confusing.
* Replace string concatenation with url.URL{}.String() so the helper
  uses the standard-library URL builder instead of hand-rolled
  formatting.

Net effect on the only real-world deployment: byte-for-byte identical
output. The two unit tests that previously exercised the removed
X-Forwarded-Proto fallback now pass defaultScheme directly, matching
how real callers always supply it.
* Drop the stale "fallback for local-dev contexts" sentence in the
  ExtractOAuth2 doc comment. The corresponding fallback chain in
  buildDynamicRedirectURI was removed in a previous commit; the doc
  no longer matched the code.
* Use slices.Contains in place of a manual loop when matching the
  request Host against the allowlist.
* On the OIDC token exchange path, validate the OAuth2RedirectURICookie
  against a freshly-recomputed expected redirect_uri rather than
  forwarding the cookie value unchecked. If the cookie is missing or
  does not match, return 4xx instead of silently falling back to the
  static config redirect_uri (which would mismatch the authorization
  request and produce a confusing IdP rejection). This is defense in
  depth on top of the IdP's own redirect_uri allowlist.
* Annotate the per-request log entry with oidc_rejected_reason and
  related fields on both rejection paths (disallowed host, missing
  cookie, cookie mismatch) so operators can grep / alert on rejected
  OIDC logins without code changes. Uses the existing context-based
  loggermw.RequestLoggerFromContext pattern, no new function args.
* Add a TestServer/OIDC/RedirectAllowedHosts test in cli/server_test.go
  that verifies the new flag flows from the CLI through to the running
  deployment config.
* Add unit tests for the two new rejection paths (missing redirect_uri
  cookie and mismatched redirect_uri cookie).
* gofmt: align field column widths in cli/server.go after the new
  RedirectDefaultScheme field made one of the keys longer.
* lint: drop the unused method receiver name on exchangeAssertingProvider.AuthCodeURL
  (revive: unused-receiver).
* gen: add the OAuth2RedirectURICookie const to site/src/api/typesGenerated.ts;
  add the redirect_allowed_hosts entry to the example response in
  docs/reference/api/general.md.
* lint-docs: reformat the codersdk.OIDCConfig properties table in
  docs/reference/api/schemas.md so every column is padded to the
  longest cell, which is what markdown-table-formatter expects after
  the new redirect_allowed_hosts row introduced a longer description.
@Shelnutt2
Shelnutt2 force-pushed the feat/oidc-redirect-allowed-hosts branch from ddac0d2 to a68a343 Compare June 27, 2026 13:07
The description column max width (442 chars from redirect_allowed_hosts)
was not reflected in the separator (356 dashes). Reformat so all column
separators match their per-column content width.
auto-merge was automatically disabled July 3, 2026 22:04

Head branch was pushed to by a user without write access

@ibetitsmike
ibetitsmike merged commit d7ad85f into coder:main Jul 5, 2026
29 of 33 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 5, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

community Pull Requests and issues created by the community.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants