Skip to content

fix: serve the OAuth discovery document without authentication - #1095

Open
thomasvvugt wants to merge 1 commit into
projectcapsule:mainfrom
thomasvvugt:oauth-discovery-metadata
Open

fix: serve the OAuth discovery document without authentication#1095
thomasvvugt wants to merge 1 commit into
projectcapsule:mainfrom
thomasvvugt:oauth-discovery-metadata

Conversation

@thomasvvugt

Copy link
Copy Markdown

oc login <proxy-host> --web (and any client using the OAuth authorization code flow) requests /.well-known/oauth-authorization-server from the API endpoint before it has any credentials. The proxy requires authentication to resolve the user on every request, so this request was rejected and the login aborted before the browser flow could even start (oc then fails with a confusing unsupported protocol scheme "").

The upstream API server already serves this document for anonymous requests, so the proxy can simply forward it. This registers the path on the top-level router next to /_healthz, outside the authenticated subrouter, and hands it to the reverse proxy.

Validated against an OpenShift cluster (Hypershift-hosted control plane, Kubernetes 1.33):

  • GET /.well-known/oauth-authorization-server without credentials: 200 with the cluster OAuth metadata, identical to the API server response
  • GET /version and GET /api/v1/namespaces without credentials: still 403, the authentication requirement is unchanged for everything else
  • authenticated tenant-scoped listing through the proxy: unchanged

With this in place oc login <proxy-host> --web completes against capsule-proxy on OpenShift: discovery succeeds, the browser flow runs against the cluster OAuth server, and the token exchange and API traffic go through the proxy as usual.

Unrelated but worth flagging while testing: main currently panics on startup when no bearer token is configured (bearerExpirationTime dereferences the nil token returned by the jwt v5 ParseUnverified on empty input, webserver.go:826-827). I carried a local nil guard to run the validation above; happy to send that as a separate PR if useful.

Copilot AI lite review requested due to automatic review settings August 27, 2026 07:02
@thomasvvugt thomasvvugt changed the title Serve the OAuth discovery document without authentication fix: serve the OAuth discovery document without authentication Aug 27, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the web server router to serve the OpenShift OAuth discovery document (/.well-known/oauth-authorization-server) without requiring prior authentication, enabling oc login <proxy-host> --web and other OAuth authorization-code clients to complete their initial discovery step successfully through the proxy.

Changes:

  • Registers /.well-known/oauth-authorization-server on the top-level router (outside the authenticated subrouter).
  • Forwards that endpoint directly to the upstream API server via the existing reverse proxy.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread internal/webserver/webserver.go Outdated
@thomasvvugt
thomasvvugt force-pushed the oauth-discovery-metadata branch from a2ea64f to 4f536ef Compare August 27, 2026 07:05
Clients that use the OAuth authorization code flow, such as
'oc login <host> --web', retrieve /.well-known/oauth-authorization-server
from the API endpoint before any credentials exist. The proxy rejected
these requests because user resolution requires authentication, so the
login aborted before the browser flow could start.

The upstream API server already answers this path anonymously, so
register it on the top-level router, like /_healthz, and hand it to the
reverse proxy.

Signed-off-by: Thomas van Vugt <thomas.vugt@rvig.nl>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

@oliverbaehler

Copy link
Copy Markdown
Collaborator

We should implement this more generic, instead of having that single path we should add a slice var as argument where paths can be provided, which are passed. We already have allowedPaths in the main but it was not properly implement. I can take a look at that.

@thomasvvugt

Copy link
Copy Markdown
Author

Hi, makes sense. Happy to rework this PR onto a flag (e.g. --unauthenticated-paths or extending allowedPaths with a separate unauthenticated set), or leave it to you. I can validate against our cluster.

@oliverbaehler

Copy link
Copy Markdown
Collaborator

You will need the following args:

--allowed-paths="/api"
--allowed-paths="/apis"
--allowed-paths="/version"
--allowed-paths="/.well-known/oauth-authorization-server"

@thomasvvugt Can you verify with changes in #1096

@thomasvvugt

Copy link
Copy Markdown
Author

Verified #1096 against our cluster; the binding fix works, but anonymous requests still get rejected before the allowed-paths check.

It looks like the auth-type loop in internal/request/http.go skips Anonymous explicitly ("capsule-proxy does not support unauthenticated users"), and that happens upstream of CheckPaths. Adding --ignored-user-group=system:unauthenticated doesn't help either, since the rejection is before any group evaluation.

When we are using oc login --web, it needs the discovery before any credentials exist, so some form of unauthenticated passthrough for allowed paths is still required. Happy to rebase #1095 on main.

@oliverbaehler

Copy link
Copy Markdown
Collaborator

@thomasvvugt Forgot about the authentication, but another bug fixed. Can you try this, is now a dedicated flag:
#1098

@thomasvvugt

Copy link
Copy Markdown
Author

Validated #1098 against our cluster with --public-paths=/.well-known/oauth-authorization-server.
This fixes our use case. Thanks, looking forwarding to seeing this in an upcoming version, happy to close #1095 in favour of this.

@oliverbaehler

Copy link
Copy Markdown
Collaborator

@thomasvvugt will be released today, do you think we should expand the oc docs with this case?
https://projectcapsule.dev/docs/operating/setup/openshift/

@thomasvvugt

Copy link
Copy Markdown
Author

Hi @oliverbaehler , yes please, a short section on that page would help. The pieces that mattered for us:

  • the symptom: oc login --web aborts with unsupported protocol scheme because the discovery document is fetched before any credentials exist
  • the fix: --public-paths=/.well-known/oauth-authorization-server, a note that the token exchange still runs against the cluster OAuth server, so clients must trust that cluster's root CA
  • the limitation note on RFE-7592 further down that page could be softened too: with --web working against the proxy, the console "copy login command" workaround is no longer the only option 😊

Happy to write the section as a PR against the docs, we validated the full flow against a HyperShift (HostedControlPlane) cluster with exactly that flag.

@oliverbaehler

Copy link
Copy Markdown
Collaborator

@thomasvvugt if you have time contributing to the docs that would be great

@thomasvvugt

Copy link
Copy Markdown
Author

Picked up the docs suggestion: projectcapsule/website#131 adds a hosted-control-planes section for the oc login --web flow. Thanks for the quick help on this!

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.

3 participants