Proxy /oauth/register to the IAM Auth service
Related to #602404
Blocked by: gitlab-org/cells/http-router!1418 (merged)
Closes a part of #623577
What?
Workhorse routes POST /oauth/register by a new register_routing internal endpoint:
- when the
proxy_dcr_to_iamfeature flag (default off, rollout #631994) is enabled for the request and - when the IAM_SERVICE_URL is set.
The registration is proxied to the IAM Auth service otherwise it stays on Rails. A failed decision call fails safe to Rails.
- Each registration logs one
oauthproxy: routing decisionline:destination=iamwithreason=dynamic_client_registration, ordestination=railswithreason=dynamic_client_registration_ff_disabled.
Why?
See MR 1's Why.
proxy_dcr_to_iam is the DCR cutover switch, independent of IAM_SERVICE_URL (which wires all IAM routing) and of proxy_oauth_requests_to_iam_service (whose actor is the OAuth application, so the only state register could read is the global one, which also moves every application's authorize). !256842 (merged) (MR 1) has to be deployed before the flag is enabled.
Screenshots & Recordings
| Scenario | Demo |
|---|---|
POST /oauth/register through GDK lands on IAM |
|
IAM_SERVICE_URL unset, registration stays on Rails |
The recordings predate the
proxy_dcr_to_iamgate; with the gate in place, the IAM run additionally has the flag enabled.
How to set up and validate locally
Note: In the steps below, GDK is
https://gdk.test:8080and the IAM service ishttp://gdk.test:8084. Adjust the URLs to match your local configuration.
Steps
1. Start IAM and point Workhorse at it
-
Start IAM, step 1 of gitlab-org/auth/iam!560 (merged):
cd ~/iam && mise exec -- make run-auth # {"component":"auth_http","level":"info","msg":"listening on :8084"} -
Build Workhorse from this branch and point it at IAM.
IAM_SERVICE_URLis the existing Workhorse switch for all IAM routing, production sets it, GDK does not:cd ~/gitlab-development-kit mise exec -- make -C gitlab/workhorse echo 'export IAM_SERVICE_URL=http://gdk.test:8084' >> env.runit mise exec -- gdk restart gitlab-workhorse rails-web grep 'OAuth routing to IAM service enabled' log/gitlab-workhorse/current | tail -1 # {"msg":"oauthproxy: OAuth routing to IAM service enabled","iam_routing_enabled":true,"iam_backend_url":"http://gdk.test:8084"} -
Enable the DCR routing flag:
cd ~/gitlab-development-kit/gitlab bin/rails runner 'Feature.enable(:proxy_dcr_to_iam)'
2. Good path, registration lands on IAM
curl -X POST https://gdk.test:8080/oauth/register -H 'Content-Type: application/json' \
-d '{"client_name":"MCP Client","redirect_uris":["http://localhost:1234/cb"]}'
# {"client_id":"<...>","client_id_issued_at":<...>,"redirect_uris":["http://localhost:1234/cb"],"token_endpoint_auth_method":"none","grant_types":["authorization_code","refresh_token"],"client_name":"[Unverified Dynamic Application] MCP Client","scope":"mcp"}
grep 'oauthproxy: routing decision' log/gitlab-workhorse/current | tail -1
# {"destination":"iam","method":"POST","msg":"oauthproxy: routing decision","path":"/oauth/register","reason":"dynamic_client_registration"}
CLIENT_ID=""
PGPASSWORD=iam-service psql -h localhost -p 5430 -U iam-service iam-service \
-c "SELECT id, scopes, public, dynamic FROM oauth_clients WHERE id = '$CLIENT_ID';"
# one row, scopes ["mcp"], public t, dynamic t3. Bad path, flag disabled, registration stays on Rails
cd ~/gitlab-development-kit/gitlab && bin/rails runner 'Feature.disable(:proxy_dcr_to_iam)'
curl -X POST https://gdk.test:8080/oauth/register -H 'Content-Type: application/json' \
-d '{"client_name":"MCP Client","redirect_uris":["http://localhost:1234/cb"]}'
# {"client_id":"<...>",...,"grant_types":["authorization_code"],"require_pkce":true,...,"dynamic":true}
grep 'oauthproxy: routing decision' log/gitlab-workhorse/current | tail -1
# {"destination":"rails","method":"POST","msg":"oauthproxy: routing decision","path":"/oauth/register","reason":"dynamic_client_registration_ff_disabled"}
CLIENT_ID=""
mise exec -- gdk psql -c "SELECT uid, name, dynamic FROM oauth_applications WHERE uid = '$CLIENT_ID';"
# one row, name [Unverified Dynamic Application] MCP Client, dynamic t4. Bad path, IAM_SERVICE_URL unset, registration stays on Rails
sed -i '' '/IAM_SERVICE_URL/d' env.runit
mise exec -- gdk restart gitlab-workhorse rails-web
curl -X POST https://gdk.test:8080/oauth/register -H 'Content-Type: application/json' \
-d '{"client_name":"MCP Client","redirect_uris":["http://localhost:1234/cb"]}'
# {"client_id":"<...>",...,"grant_types":["authorization_code"],"require_pkce":true,...,"dynamic":true}
grep 'oauthproxy:' log/gitlab-workhorse/current | tail -1
# {"msg":"oauthproxy: IAMServiceURL not set; OAuth requests will be handled by Rails","iam_routing_enabled":false}
CLIENT_ID=""
mise exec -- gdk psql -c "SELECT uid, name, dynamic FROM oauth_applications WHERE uid = '$CLIENT_ID';"
# one row, name [Unverified Dynamic Application] MCP Client, dynamic tMR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.