Skip to content

feat: add external base url support for reverse proxy mcp oauth#3088

Merged
akshaydeo merged 1 commit intomainfrom
04-27-feat_add_external_base_url_support_in_per_user_oauth_flows
Apr 28, 2026
Merged

feat: add external base url support for reverse proxy mcp oauth#3088
akshaydeo merged 1 commit intomainfrom
04-27-feat_add_external_base_url_support_in_per_user_oauth_flows

Conversation

@Pratham-Mishra04
Copy link
Copy Markdown
Collaborator

Summary

When Bifrost runs behind a reverse proxy, OAuth callback URLs and well-known discovery endpoints (/.well-known/oauth-authorization-server, /.well-known/oauth-protected-resource) were being built from the incoming Host header, which reflects the proxy's internal address rather than its public-facing URL. This PR introduces mcp_external_base_url to override that derived URL with the proxy's public base URL.

Changes

  • Added mcp_external_base_url field to ClientConfig (Go struct, DB table, JSON schema, OpenAPI schema, and config.schema.json) supporting both plain URL strings and env var references ("env.MY_VAR").
  • Introduced lib.BuildBaseURL(ctx, externalBaseURL) as a single helper that centralizes base URL resolution — using the configured override when present, falling back to the X-Forwarded-Proto/Host-derived URL otherwise. Replaced all inline scheme+host construction across mcp.go, mcpserver.go, oauth2_metadata.go, oauth2_per_user.go, and ctx.go with calls to this helper.
  • Added a DB migration (migrationAddMCPExternalBaseURLColumn) to add the mcp_external_base_url column to the client config table.
  • Wired GetMCPExternalBaseURL() into the HandlerStore interface and implemented it on Config; updated all test stubs accordingly.
  • Exposed the setting in the management API config update handler so it can be changed without a restart.
  • Added an External Base URL field to the UI under Config → Client Settings (MCP view) using EnvVarInput, with change detection and RBAC gating.
  • Documented the field in docs/deployment-guides/config-json/client.mdx and schema-reference.mdx with usage examples for both plain URL and env var forms.

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (React)
  • Docs

How to test

# Core/Transports
go test ./...

# UI
cd ui
pnpm i
pnpm build

Manual validation:

  1. Deploy Bifrost behind a reverse proxy (e.g. nginx) where the public URL differs from the internal Host header.
  2. Set mcp_external_base_url in config.json or via the UI (Config → Client Settings → Proxy Settings):
    { "client": { "mcp_external_base_url": "https://api.yourcompany.com" } }
  3. Trigger an MCP OAuth flow and confirm the redirect URI and /.well-known/oauth-authorization-server issuer both reflect https://api.yourcompany.com rather than the internal host.
  4. Test env var form: set mcp_external_base_url to "env.BIFROST_EXTERNAL_URL", export the env var, and confirm the resolved URL is used.
  5. Clear the field and confirm fallback to the Host-header-derived URL.

New config field:

Field Type Description
mcp_external_base_url string | EnvVar Public base URL for OAuth callbacks and discovery metadata when behind a reverse proxy. Supports "env.MY_VAR" syntax.

Breaking changes

  • Yes
  • No

Related issues

Security considerations

The mcp_external_base_url value is used to construct OAuth redirect URIs and discovery metadata URLs. Only trusted administrators with config update access can set this value (RBAC-gated in the UI; management API access required via API). Env var references are resolved server-side and never exposed to clients.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 27, 2026

Warning

Rate limit exceeded

@akshaydeo has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 4 minutes and 2 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e6a96ea6-e3f4-4c68-9293-5aa621391149

📥 Commits

Reviewing files that changed from the base of the PR and between 4c22bb3 and f23102b.

📒 Files selected for processing (22)
  • docs/deployment-guides/config-json/client.mdx
  • docs/deployment-guides/config-json/schema-reference.mdx
  • docs/openapi/openapi.json
  • docs/openapi/schemas/management/config.yaml
  • framework/configstore/clientconfig.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/tables/clientconfig.go
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/handlers/mcp.go
  • transports/bifrost-http/handlers/mcpserver.go
  • transports/bifrost-http/handlers/oauth2_metadata.go
  • transports/bifrost-http/handlers/oauth2_per_user.go
  • transports/bifrost-http/handlers/webrtc_realtime_test.go
  • transports/bifrost-http/handlers/wsresponses_test.go
  • transports/bifrost-http/integrations/bedrock_test.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/ctx.go
  • transports/bifrost-http/lib/ctx_test.go
  • transports/config.schema.json
  • ui/app/workspace/config/views/mcpView.tsx
  • ui/lib/types/config.ts
📝 Walkthrough

Walkthrough

Adds a new configuration field mcp_external_base_url to specify the externally reachable base URL for MCP OAuth callbacks and discovery metadata when operating behind a reverse proxy. The field supports environment variable injection and can be updated via UI/management API without restarting. Changes span docs, DB, backend, handlers, and UI.

Changes

Cohort / File(s) Summary
Documentation
docs/deployment-guides/config-json/client.mdx, docs/deployment-guides/config-json/schema-reference.mdx, docs/openapi/schemas/management/config.yaml, transports/config.schema.json, docs/openapi/openapi.json
Adds docs and OpenAPI/JSON schema entries for client.mcp_external_base_url, documenting env-var and literal forms for reverse-proxy deployments.
Core Configuration Storage
framework/configstore/clientconfig.go, framework/configstore/tables/clientconfig.go, framework/configstore/migrations.go, framework/configstore/rdb.go
Adds MCPExternalBaseURL to ClientConfig and persisted table, migration to add column, and conversion logic to/from schemas.EnvVar for DB round-trips and hashing.
Configuration Persistence & Retrieval
transports/bifrost-http/handlers/config.go, transports/bifrost-http/lib/config.go
Propagates new field through update handler and exposes GetMCPExternalBaseURL() on HandlerStore/Config to resolve env-backed values.
OAuth & Metadata Handlers
transports/bifrost-http/handlers/mcp.go, transports/bifrost-http/handlers/mcpserver.go, transports/bifrost-http/handlers/oauth2_metadata.go, transports/bifrost-http/handlers/oauth2_per_user.go
Switches redirect URI and metadata base URL construction to use centralized BuildBaseURL() that prefers configured external base URL over request-derived scheme/host.
Base URL Construction
transports/bifrost-http/lib/ctx.go
Introduces BuildBaseURL(ctx, externalBaseURL) to centralize base URL resolution and to set OAuth redirect URI in request context when available.
Test Doubles & Tests
transports/bifrost-http/handlers/webrtc_realtime_test.go, transports/bifrost-http/handlers/wsresponses_test.go, transports/bifrost-http/integrations/bedrock_test.go, transports/bifrost-http/lib/ctx_test.go
Updates test mocks to implement GetMCPExternalBaseURL() so tests compile against the expanded HandlerStore interface.
UI Configuration
ui/app/workspace/config/views/mcpView.tsx, ui/lib/types/config.ts
Adds mcp_external_base_url to UI types and the MCP settings view with env-var-aware input and change detection for value/env_var/from_env.

Sequence Diagram

sequenceDiagram
    participant UI as User/UI
    participant Handler as Config Handler
    participant Store as Config Store
    participant DB as Database
    participant OAuth as OAuth/Metadata Handlers
    participant Client as Downstream MCP Client

    UI->>Handler: Submit updated mcp_external_base_url
    Handler->>Store: UpdateClientConfig(updatedConfig)
    Store->>DB: Persist MCPExternalBaseURL
    DB-->>Store: Persisted
    Store-->>Handler: Update confirmed
    Handler-->>UI: Success

    Client->>OAuth: Request OAuth callback / metadata
    OAuth->>Store: GetMCPExternalBaseURL()
    Store-->>OAuth: External base URL (resolved from env-var or literal)
    OAuth->>OAuth: BuildBaseURL(ctx, externalBaseURL)
    OAuth-->>Client: Redirect URI / metadata with resolved base URL
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐰 I found a base URL, tidy and bright,
No more guessing through proxy by night,
Callbacks now land where they should, steady and true,
Env-vars or literals — I hop and I knew,
Config saved, metadata sings: onward we flew.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main feature: adding external base URL support for reverse proxy MCP OAuth flows. It is concise and specific about the primary change.
Description check ✅ Passed The PR description comprehensively covers all required sections: clear summary, detailed changes, feature type checkbox marked, affected areas identified, testing instructions, security considerations, and completed checklist items.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 04-27-feat_add_external_base_url_support_in_per_user_oauth_flows

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 27, 2026

Confidence Score: 5/5

Safe to merge; no P0/P1 issues found

All previously flagged issues (JSON tag mismatch, empty-host guard) are resolved in the current HEAD. The only remaining finding is a P2 UX concern about silent fallback on malformed override URLs. Core DB round-trip, env var resolution, and request-path logic are correct.

No files require special attention

Important Files Changed

Filename Overview
transports/bifrost-http/lib/ctx.go Adds BuildBaseURL helper with proper comma-aware X-Forwarded-Proto parsing and empty-host guard returning ""
framework/configstore/rdb.go Adds mcpExternalBaseURLToString which correctly uses driver.Valuer to preserve env var references in DB storage; load path correctly uses NewEnvVar
framework/configstore/clientconfig.go Adds MCPExternalBaseURL *schemas.EnvVar with correct json:"mcp_external_base_url" tag; hash function properly differentiates env refs from plain values
transports/bifrost-http/handlers/config.go Wires MCPExternalBaseURL through the config update handler; nil assignment correctly clears the override
transports/bifrost-http/handlers/mcp.go Replaces duplicate inline scheme+host construction with lib.BuildBaseURL; no logic change for the non-empty-host case
transports/bifrost-http/handlers/oauth2_metadata.go Consolidates baseURL construction to lib.BuildBaseURL; issuer/resource URIs now respect the external override
transports/bifrost-http/handlers/oauth2_per_user.go Replaces inline scheme+host construction with lib.BuildBaseURL for the upstream authorize redirect URI
ui/app/workspace/config/views/mcpView.tsx Adds External Base URL field with EnvVarInput, RBAC gating, and correct three-field change detection
framework/configstore/migrations.go Adds idempotent column migration for mcp_external_base_url with rollback support; correctly ordered
framework/configstore/tables/clientconfig.go Adds MCPExternalBaseURL string with correct json:"mcp_external_base_url" tag and varchar(512) column type

Reviews (4): Last reviewed commit: "feat: add external base url support in p..." | Re-trigger Greptile

Comment thread framework/configstore/clientconfig.go Outdated
Comment thread framework/configstore/tables/clientconfig.go Outdated
Comment thread transports/bifrost-http/lib/ctx.go Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/deployment-guides/config-json/client.mdx`:
- Line 83: The UI navigation path in the sentence that currently reads "Config →
Client Settings → Proxy Settings" is incorrect; update that text to point to the
actual location in the interface (the MCP settings view) so users are directed
correctly—for example replace the "Config → Client Settings → Proxy Settings"
fragment with the correct path referencing the MCP settings view (e.g., "Config
→ MCP Settings" or the exact menu label used in the app) within the line in
docs/deployment-guides/config-json/client.mdx.

In `@docs/openapi/schemas/management/config.yaml`:
- Around line 97-112: Update the Go struct tag for
ClientConfig.MCPExternalBaseURL so its JSON tag is "mcp_external_base_url"
(replace the incorrect "external_base_url") so serialized API output matches the
OpenAPI schema, and in the OpenAPI schema for mcp_external_base_url add
"additionalProperties: false" to the object branch to match config.schema.json
and prevent extra fields.

In `@framework/configstore/clientconfig.go`:
- Line 78: The struct field MCPExternalBaseURL has the wrong JSON tag key;
update its tag from json:"external_base_url,omitempty" to
json:"mcp_external_base_url,omitempty" so encoding/decoding uses the correct
config key (modify the tag on the MCPExternalBaseURL field in clientconfig.go).
- Around line 317-319: The hash currently uses only
c.MCPExternalBaseURL.GetValue(), which loses whether the value came from an env
var; change the hashing to include a source prefix so env-backed and literal
inputs differ (e.g., write "externalBaseURL:env:<value>" when the entry is from
an environment variable and "externalBaseURL:val:<value>" when it is a literal).
Concretely, update the block that references c.MCPExternalBaseURL (use its
existing helper such as IsSet()/IsFromEnv()/IsEnv() or equivalent) to choose the
"env:" vs "val:" prefix before hashing, then write the prefixed string to hash
instead of only GetValue().

In `@transports/bifrost-http/lib/ctx.go`:
- Around line 653-661: BuildBaseURL currently accepts any non-empty
externalBaseURL (e.g., "/" or "  /"), producing invalid base URLs; instead
validate the override: trim whitespace, reject values that are just "/" or lack
an absolute scheme/host, and only use the override when it is a well-formed
absolute URL (or at least starts with "http://" or "https://"); otherwise fall
back to the existing ctx-derived logic (using ctx.IsTLS and ctx.Host()). Update
BuildBaseURL to sanitize externalBaseURL, confirm its scheme/host (e.g., via
url.Parse or strings.HasPrefix checks), trim trailing slashes, and only return
the override when valid.

In `@ui/app/workspace/config/views/mcpView.tsx`:
- Around line 341-349: Add a stable test selector prop to the new EnvVarInput so
E2E tests can target it: update the EnvVarInput instance
(id="external-base-url", value bound to localConfig.mcp_external_base_url and
onChange handler) to include a data-testid prop with a clear name such as
"mcp-external-base-url-input"; ensure the prop is passed directly to the
EnvVarInput component so it appears on the rendered input element and respect
existing disabled logic (disabled={!hasSettingsUpdateAccess}).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1fecddfb-a2af-4568-9335-a01a9bc6115b

📥 Commits

Reviewing files that changed from the base of the PR and between e1baf67 and 4c5ed3a.

📒 Files selected for processing (21)
  • docs/deployment-guides/config-json/client.mdx
  • docs/deployment-guides/config-json/schema-reference.mdx
  • docs/openapi/schemas/management/config.yaml
  • framework/configstore/clientconfig.go
  • framework/configstore/migrations.go
  • framework/configstore/rdb.go
  • framework/configstore/tables/clientconfig.go
  • transports/bifrost-http/handlers/config.go
  • transports/bifrost-http/handlers/mcp.go
  • transports/bifrost-http/handlers/mcpserver.go
  • transports/bifrost-http/handlers/oauth2_metadata.go
  • transports/bifrost-http/handlers/oauth2_per_user.go
  • transports/bifrost-http/handlers/webrtc_realtime_test.go
  • transports/bifrost-http/handlers/wsresponses_test.go
  • transports/bifrost-http/integrations/bedrock_test.go
  • transports/bifrost-http/lib/config.go
  • transports/bifrost-http/lib/ctx.go
  • transports/bifrost-http/lib/ctx_test.go
  • transports/config.schema.json
  • ui/app/workspace/config/views/mcpView.tsx
  • ui/lib/types/config.ts

Comment thread docs/deployment-guides/config-json/client.mdx Outdated
Comment thread docs/openapi/schemas/management/config.yaml
Comment thread framework/configstore/clientconfig.go Outdated
Comment thread framework/configstore/clientconfig.go
Comment thread transports/bifrost-http/lib/ctx.go Outdated
Comment thread ui/app/workspace/config/views/mcpView.tsx
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 04-27-feat_add_external_base_url_support_in_per_user_oauth_flows branch from 4c5ed3a to 4c22bb3 Compare April 28, 2026 06:04
coderabbitai[bot]
coderabbitai Bot previously approved these changes Apr 28, 2026
Copy link
Copy Markdown
Contributor

akshaydeo commented Apr 28, 2026

Merge activity

@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 04-27-feat_add_external_base_url_support_in_per_user_oauth_flows branch from 4c22bb3 to 6df9fea Compare April 28, 2026 07:07
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the 04-27-fix_list_models_log_sheet_ui_fixes branch from e1baf67 to 930c72d Compare April 28, 2026 07:07
@akshaydeo akshaydeo changed the base branch from 04-27-fix_list_models_log_sheet_ui_fixes to graphite-base/3088 April 28, 2026 07:27
@akshaydeo akshaydeo changed the base branch from graphite-base/3088 to main April 28, 2026 07:27
@akshaydeo akshaydeo dismissed coderabbitai[bot]’s stale review April 28, 2026 07:27

The base branch was changed.

@akshaydeo akshaydeo force-pushed the 04-27-feat_add_external_base_url_support_in_per_user_oauth_flows branch from 6df9fea to f23102b Compare April 28, 2026 07:28
@akshaydeo akshaydeo merged commit 0de154c into main Apr 28, 2026
14 of 19 checks passed
@akshaydeo akshaydeo deleted the 04-27-feat_add_external_base_url_support_in_per_user_oauth_flows branch April 28, 2026 07:29
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