Skip to content

feat(auth): support separate OIDC discovery URL for back-channel calls#369

Merged
aktech merged 4 commits into
mainfrom
feat/oidc-separate-discovery-url
Jun 4, 2026
Merged

feat(auth): support separate OIDC discovery URL for back-channel calls#369
aktech merged 4 commits into
mainfrom
feat/oidc-separate-discovery-url

Conversation

@viniciusdc

@viniciusdc viniciusdc commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Closes #371

What

Adds an optional oidc_discovery_url (NEBI_AUTH_OIDC_DISCOVERY_URL) that decouples where nebi fetches .well-known/openid-configuration from the issuer it validates in the token's iss claim.

Why

In split-horizon deployments the public issuer URL that browsers use is not resolvable from inside the cluster. Today nebi uses a single oidc_issuer_url for both discovery and iss validation, so OIDC init fails on the discovery fetch and loops forever:

"msg":"OIDC initialization retry failed, will try again",
"error":"failed to discover OIDC provider: Get \"https://keycloak.<redacted>/realms/nebari/.well-known/openid-configuration\": dial tcp: lookup keycloak.<redacted> on 172.20.0.10:53: no such host"

This came up deploying the nebari-nebi-pack into a private cluster where Keycloak sits behind an external gateway (browsers can reach it, in-cluster pods can't). See nebari-dev/nebari-nebi-pack#13.

How

When oidc_discovery_url is set, discovery is fetched from it (e.g. an in-cluster Keycloak Service) while iss is still validated against oidc_issuer_url, using oidc.InsecureIssuerURLContext to tell go-oidc the two are intentionally different. When unset, behavior is unchanged — discovery and issuer validation both use oidc_issuer_url.

auth:
  oidc_issuer_url:    https://keycloak.example.com/realms/nebari            # public; validated in "iss"
  oidc_discovery_url: http://keycloak-http.keycloak.svc.cluster.local/realms/nebari  # in-cluster; discovery fetch

Operator note

This is the same issuer-vs-discovery split that nebari-dev/nebari-operator#112 is tracking for the gateway's SecurityPolicy.oidc. This PR covers nebi's own direct OIDC (used by the CLI device-code flow); the two should stay consistent.

Deployment caveat (not a code concern)

Discovery is necessary but not sufficient. After discovery, the endpoints in the document (token_endpoint, jwks_uri) are what nebi calls for code exchange and token verification. The IdP must return in-cluster-reachable URLs for those — for Keycloak that means hostname-backchannel-dynamic=true (KC_HOSTNAME_STRICT_BACKCHANNEL=false) so that fetching discovery via the internal URL echoes internal back-channel URLs. nebi leaves the endpoints as the IdP returns them.

Tests

internal/auth/oidc_test.go:

  • discovery via DiscoveryURL with a mismatched (public) issuer succeeds
  • the default path (no DiscoveryURL) still rejects an iss that doesn't match the discovery URL

go test ./internal/auth/..., go vet, and gofmt all clean.

Related Issues

Add an optional oidc_discovery_url (NEBI_AUTH_OIDC_DISCOVERY_URL) that
decouples where nebi fetches .well-known/openid-configuration from the
issuer it validates in the token's "iss" claim.

In split-horizon deployments the public issuer URL that browsers use may
not be resolvable from inside the cluster, so OIDC initialization fails on
the discovery fetch and never recovers. When oidc_discovery_url is set,
discovery is fetched from it (e.g. an in-cluster Keycloak Service) while
"iss" is still validated against oidc_issuer_url, using
oidc.InsecureIssuerURLContext to tell go-oidc the two are intentionally
different. When unset, behavior is unchanged: discovery and issuer
validation both use oidc_issuer_url.
@netlify

netlify Bot commented Jun 1, 2026

Copy link
Copy Markdown

Deploy Preview for nebi-docs canceled.

Name Link
🔨 Latest commit 4fe892d
🔍 Latest deploy log https://app.netlify.com/projects/nebi-docs/deploys/6a20546b56c12f00080c883f

@aktech aktech merged commit 32d0bc9 into main Jun 4, 2026
14 checks passed
@aktech aktech deleted the feat/oidc-separate-discovery-url branch June 4, 2026 06:52
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.

OIDC discovery fails in split-horizon deployments (in-cluster pods can't reach public issuer)

2 participants