Fix MCP OAuth discovery failing on relative URL installs

Summary

On relative URL installs (e.g. external_url 'https://example.com/gitlab'), the /.well-known/oauth-authorization-server metadata response is missing registration_endpoint. This breaks MCP clients that rely on RFC 7591 Dynamic Client Registration — they fail with:

Incompatible auth server: does not support dynamic client registration

Root Cause

JwksController#provider uses request.path to check whether the current request matches OAUTH_PATHS:

if request.path.in?(OAUTH_PATHS)

With a relative URL install, Rails sets SCRIPT_NAME=/gitlab and strips it from PATH_INFO. However, request.path returns SCRIPT_NAME + PATH_INFO, so the value is /gitlab/.well-known/oauth-authorization-server — which does not match the entries in OAUTH_PATHS (/.well-known/oauth-authorization-server).

As a result, registration_endpoint is never added to the OAuth metadata, and the method falls through to super (the Doorkeeper default which doesn't include it).

The same issue affects the provider_response method's MCP scope filtering on line 64.

Evidence

Tested on a GitLab 18.8.4-ee instance with external_url 'https://host/gitlab':

Before fixrequest.path = /gitlab/.well-known/oauth-authorization-server:

// GET /gitlab/.well-known/oauth-authorization-server
// registration_endpoint is MISSING
{
  "issuer": "https://host/gitlab",
  "authorization_endpoint": "https://host/gitlab/oauth/authorize",
  "token_endpoint": "https://host/gitlab/oauth/token"
}

After fixrequest.path_info = /.well-known/oauth-authorization-server:

// GET /gitlab/.well-known/oauth-authorization-server
{
  "issuer": "https://host/gitlab",
  "authorization_endpoint": "https://host/gitlab/oauth/authorize",
  "token_endpoint": "https://host/gitlab/oauth/token",
  "registration_endpoint": "https://host/gitlab/oauth/register"
}

Non-relative URL installs are unaffected — when SCRIPT_NAME is empty, request.path and request.path_info return identical values:

# Non-relative URL install (SCRIPT_NAME = '')
request.path:      /.well-known/oauth-authorization-server
request.path_info: /.well-known/oauth-authorization-server
→ Both match OAUTH_PATHS ✓

# Relative URL install (SCRIPT_NAME = '/gitlab')
request.path:      /gitlab/.well-known/oauth-authorization-server  → no match ✗
request.path_info: /.well-known/oauth-authorization-server         → match ✓

Fix

Replace request.path with request.path_info in two places in JwksController:

  • Line 23: the OAUTH_PATHS membership check in #provider
  • Line 64: the .end_with?('/api/v4/mcp') check in #provider_response

Testing

  • Verified registration_endpoint appears in metadata on relative URL install
  • Verified MCP client (mcp-remote) successfully performs dynamic client registration and reaches the OAuth authorize flow
  • Verified non-relative URL installs are unaffected (request.path == request.path_info when SCRIPT_NAME is empty)

Merge request reports

Loading