docs: add per-user OAuth documentation and API endpoints#2598
Conversation
|
|
📝 WalkthroughSummary by CodeRabbit
WalkthroughThis PR adds comprehensive documentation and OpenAPI specifications for per-user OAuth 2.1 support. Changes include new MCP documentation pages explaining per-user authentication workflows, updated authentication descriptions in existing guides, and extensive API endpoint definitions for OAuth authorization, consent flows, and discovery mechanisms. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
🧪 Test Suite AvailableThis PR can be tested by a repository admin. |
bb017b5 to
d6f9c40
Compare
Confidence Score: 5/5Safe to merge — all findings are P2 style/consistency issues in schema descriptions with no functional impact. The PR is documentation-only. All three comments are P2 style fixes (version string typo, stale field description, header casing). None affects correctness, data, or user-visible behavior. docs/openapi/schemas/management/mcp.yaml — oauth_config_id descriptions (3 occurrences) and MCPAuthType version string should be updated to mention per_user_oauth and OAuth 2.1 respectively.
|
| Filename | Overview |
|---|---|
| docs/mcp/per-user-oauth.mdx | New page documenting per-user OAuth 2.1 flow — well-structured and thorough, but the bash examples have inconsistent header casing (x-bf-virtual-key vs X-Bf-User-Id) |
| docs/openapi/schemas/management/mcp.yaml | MCPAuthType description uses "OAuth 2.0" for per_user_oauth (should be 2.1); oauth_config_id description in 3 places says "Only relevant when auth_type is 'oauth'" but per_user_oauth also requires this field |
| docs/openapi/schemas/management/oauth.yaml | Adds well-defined schemas for per-user OAuth 2.1: client registration, token response, protected resource metadata, and authorization server metadata — all consistent with RFC references |
| docs/openapi/paths/management/oauth.yaml | Adds 12 new endpoint definitions (RFC 7591 registration, OAuth 2.1 authorize/token, upstream proxy, consent flow pages, discovery endpoints) with complete request/response documentation |
| docs/changelogs/v1.5.0-prerelease2.mdx | Adds model alias feature entry, 3 new breaking changes table (BC #9–11), and per-module changelog entries for core, framework, and HTTP transport |
| docs/openapi/openapi.yaml | Correctly registers all 12 new per-user OAuth path references in three logical groups (Authorization Server, Consent Flow, Discovery) |
| docs/openapi/openapi.json | Auto-generated JSON bundle — includes all new per-user OAuth endpoints and schemas consistent with the YAML source |
| docs/mcp/connecting-to-servers.mdx | Updates connection type table and sections to mention per-user OAuth support for HTTP and SSE connections, with correct cross-references |
| docs/mcp/gateway-url.mdx | Adds a short section explaining how the /mcp endpoint advertises OAuth support via WWW-Authenticate headers when per_user_oauth is configured |
| docs/mcp/oauth.mdx | Adds an Info callout at the top to differentiate server-level OAuth from per-user OAuth, with a cross-reference link |
| docs/mcp/overview.mdx | Adds a Per-User OAuth card to the MCP overview navigation section |
| docs/docs.json | Adds per-user-oauth page to the MCP sidebar navigation |
Comments Outside Diff (2)
-
docs/openapi/schemas/management/mcp.yaml, line 86-91 (link)oauth_config_iddescription excludesper_user_oauthThe description says
oauth_config_idis "Only relevant when auth_type is 'oauth'", butper-user-oauth.mdxexplicitly documents thatoauth_config_idis also required whenauth_typeisper_user_oauth(the ID of the OAuth credentials created during UI setup). This same stale description appears in at least two other places in this file (around lines 196–201 and 297–302). -
docs/openapi/schemas/management/mcp.yaml, line 3-11 (link)per_user_oauthdescription says "OAuth 2.0" instead of "OAuth 2.1"The
MCPAuthTypedescription here labelsper_user_oauthas "OAuth 2.0", but the rest of the PR — theoauth.yamlschema, the path definitions, andper-user-oauth.mdx— consistently call it OAuth 2.1. The path comments even cite specific OAuth 2.1 RFCs (RFC 7636 for PKCE, RFC 7591 for Dynamic Client Registration). The description on line 11 should readPer-user OAuth 2.1 authentication (each user authenticates individually)to match.
Reviews (1): Last reviewed commit: "docs: adds docs for per user mcp oauth" | Re-trigger Greptile
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (3)
docs/openapi/openapi.json (3)
32205-32245: Consider adding 404 response for DELETE endpoint.The GET operation on this path documents a 404 response for "OAuth config not found", but the DELETE operation only documents 200 and 500. If a caller attempts to revoke a non-existent config, the expected behavior should be documented.
Suggested addition for DELETE responses
"responses": { "200": { "description": "OAuth token revoked successfully", ... }, + "404": { + "description": "OAuth config not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ManagementErrorResponse" + } + } + } + }, "500": { "description": "Internal server error", ... } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/openapi/openapi.json` around lines 32205 - 32245, The DELETE operation (operationId revokeOAuthConfig) is missing a 404 response; add a 404 entry under "responses" for the revokeOAuthConfig operation documenting "OAuth config not found" and reuse the same error schema used elsewhere (e.g., "$ref": "#/components/schemas/BifrostError") so callers know revocation can return Not Found—mirror the GET path's 404 style and content for consistency.
32336-32386: Response schema missingrequiredarray.The 201 response schema for dynamic client registration defines properties but doesn't specify which are guaranteed in the response. Per RFC 7591, at minimum
client_idis always returned. Adding arequiredarray helps API consumers know which fields to expect.Suggested addition
"schema": { "type": "object", "description": "Dynamic Client Registration response per RFC 7591", + "required": [ + "client_id" + ], "properties": { "client_id": {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/openapi/openapi.json` around lines 32336 - 32386, The response schema object for the Dynamic Client Registration response (the object that defines properties like client_id, client_name, redirect_uris, grant_types, response_types, token_endpoint_auth_method) is missing a required array; add a "required" array to that schema and include at minimum "client_id" (per RFC 7591) and any other fields that are always returned by your implementation (e.g., add "client_id" and optionally "client_name", "redirect_uris" if always present) so API consumers know which fields are guaranteed in the 201 response.
32697-32725: Clarify mutual exclusivity offlow_idandsessionparameters.Both parameters are marked as
required: false, but the description states one is required depending on the flow type. Consider adding a note at the endpoint level or in each parameter description to clarify this mutual exclusivity constraint.Suggested description enhancement
{ "name": "flow_id", "in": "query", "required": false, - "description": "Pending consent flow ID. Required if `session` is not provided.\nThe `__bifrost_flow_secret` cookie must be present and match the flow.\n", + "description": "Pending consent flow ID. **Mutually exclusive with `session`** — exactly one must be provided.\nThe `__bifrost_flow_secret` cookie must be present and match the flow.\n", "schema": { "type": "string" } }, { "name": "session", "in": "query", "required": false, - "description": "Bifrost session ID (from the token endpoint). Required if `flow_id` is not provided.\nUsed for runtime (post-consent) upstream authorization.\n", + "description": "Bifrost session ID (from the token endpoint). **Mutually exclusive with `flow_id`** — exactly one must be provided.\nUsed for runtime (post-consent) upstream authorization.\n", "schema": { "type": "string" } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/openapi/openapi.json` around lines 32697 - 32725, Update the OpenAPI operation that declares the query parameters mcp_client_id, flow_id, and session to clarify that flow_id and session are mutually exclusive and that one of them is required depending on flow type: either add a concise sentence to each parameter's description (e.g., "Mutually exclusive with `session`; one of `flow_id` or `session` must be provided.") and/or add an endpoint-level description or OpenAPI validation using oneOf/anyOf to enforce that exactly one of `flow_id` or `session` is supplied; keep mcp_client_id as required. Reference the parameter names mcp_client_id, flow_id, and session when making the change.
🤖 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/changelogs/v1.5.0-prerelease2.mdx`:
- Line 58: Replace the concatenated token "prerelease1" in the changelog
sentence with the spaced, readable form "prerelease 1" (i.e., change the phrase
"prerelease1" to "prerelease 1" in the sentence referencing prerelease1) to
improve prose consistency and readability throughout the v1.5.0-prerelease2
release notes.
In `@docs/mcp/connecting-to-servers.mdx`:
- Around line 53-57: Update the contradictory wording so OAuth 2.0 is
consistently described as admin-managed/shared: find occurrences of the phrase
"user-based authentication" (or similar) that refer to OAuth 2.0 and change them
to "admin-managed/shared token (OAuth 2.0)" or "admin-shared OAuth 2.0 token,"
and ensure "OAuth 2.0" and "Per-User OAuth" sections clearly differentiate
admin-shared vs per-user flows (adjust headings/sentences that mention
"user-based authentication" to reference admin management instead).
In `@docs/openapi/paths/management/oauth.yaml`:
- Around line 354-386: The OpenAPI docs expose the long-lived Bifrost session ID
as the query parameter "session", which leaks a bearer credential; replace this
with a short-lived opaque handoff id (e.g., "handoff_id" or "runtime_handoff")
and update the parameter block and description accordingly: remove or deprecate
the "session" parameter, add a new required/optional query parameter
"handoff_id" used only for runtime post-consent authorization, describe that it
is short-lived and single-use (server-issued by the token endpoint), and ensure
the docs reference the existing "flow_id" behavior (and the
__bifrost_flow_secret cookie) so callers know to use flow_id OR handoff_id but
never the actual session token.
- Around line 559-564: The OpenAPI OAuth endpoint currently accepts a
self-declared user_id and links it to the pending flow, which enables
impersonation; change the contract so the endpoint no longer accepts an
arbitrary persistent user_id from the public browser form but instead either (a)
require a verifiable identity source (e.g., an authenticated principal or an
upstream trusted header like X-Bf-User-Id) before persisting the ID and storing
upstream tokens, or (b) scope the submitted user_id to the browser session only
(do not persist or reuse across gateways). Update the endpoint parameter/schema
for user_id and the flow that persists tokens to enforce one of these options
and add validation checks that reject unauthenticated/self-declared persistent
IDs.
- Around line 111-123: The MCP handler currently only handles req.AuthType ==
"oauth" and doesn't support the docs' per_user_oauth flow; update the MCP
request handling (the handler around the MCP request logic that inspects
req.AuthType) to also recognize "per_user_oauth" and route it to the same OAuth
registration logic (so the operationId registerPerUserOAuthClient in the OpenAPI
can be satisfied), or alternatively make the handler return 404 for
"per_user_oauth" and update the OpenAPI docs to remove/register that operation;
adjust the conditional that checks req.AuthType (the `if req.AuthType ==
"oauth"` branch) to include the "per_user_oauth" case and ensure the existing
OAuth client-registration code path is invoked or a clear 404 is returned when
not configured.
In `@docs/openapi/schemas/management/oauth.yaml`:
- Around line 207-225: PerUserOAuthTokenResponse currently marks core fields
optional; update the OpenAPI schema (PerUserOAuthTokenResponse) to add a
required array including access_token, token_type, and expires_in, and constrain
token_type to a fixed value (e.g., enum: ["Bearer"]) so generated clients always
receive/expect those fields and the token_type is validated as "Bearer"; ensure
descriptions/examples remain unchanged for access_token, token_type, expires_in,
and scope.
- Around line 5-11: The OpenAPI enum advertises an unsupported auth type; either
remove "per_user_oauth" from the enum or implement it end-to-end: add the
MCPAuthTypePerUserOauth constant in core/schemas/mcp.go, update the
MCPClientConfig.HttpHeaders() switch to handle the new MCPAuthTypePerUserOauth
case (return appropriate headers or behavior for per-user OAuth), and add the
corresponding value/handling in the database schema code in
framework/configstore/tables/mcp.go so the DB can store and round-trip this
enum; ensure any related serialization/deserialization and docs are updated to
match.
---
Nitpick comments:
In `@docs/openapi/openapi.json`:
- Around line 32205-32245: The DELETE operation (operationId revokeOAuthConfig)
is missing a 404 response; add a 404 entry under "responses" for the
revokeOAuthConfig operation documenting "OAuth config not found" and reuse the
same error schema used elsewhere (e.g., "$ref":
"#/components/schemas/BifrostError") so callers know revocation can return Not
Found—mirror the GET path's 404 style and content for consistency.
- Around line 32336-32386: The response schema object for the Dynamic Client
Registration response (the object that defines properties like client_id,
client_name, redirect_uris, grant_types, response_types,
token_endpoint_auth_method) is missing a required array; add a "required" array
to that schema and include at minimum "client_id" (per RFC 7591) and any other
fields that are always returned by your implementation (e.g., add "client_id"
and optionally "client_name", "redirect_uris" if always present) so API
consumers know which fields are guaranteed in the 201 response.
- Around line 32697-32725: Update the OpenAPI operation that declares the query
parameters mcp_client_id, flow_id, and session to clarify that flow_id and
session are mutually exclusive and that one of them is required depending on
flow type: either add a concise sentence to each parameter's description (e.g.,
"Mutually exclusive with `session`; one of `flow_id` or `session` must be
provided.") and/or add an endpoint-level description or OpenAPI validation using
oneOf/anyOf to enforce that exactly one of `flow_id` or `session` is supplied;
keep mcp_client_id as required. Reference the parameter names mcp_client_id,
flow_id, and session when making the change.
🪄 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: fb126029-9b1e-46e1-8cfa-f55481353b0c
⛔ Files ignored due to path filters (7)
docs/media/ui-mcp-per-user-oauth-consent-identity.pngis excluded by!**/*.pngdocs/media/ui-mcp-per-user-oauth-consent-mcps.pngis excluded by!**/*.pngdocs/media/ui-mcp-per-user-oauth-flow-llm.svgis excluded by!**/*.svgdocs/media/ui-mcp-per-user-oauth-flow-mcp.svgis excluded by!**/*.svgdocs/media/ui-mcp-per-user-oauth-llm-prompt-llm.pngis excluded by!**/*.pngdocs/media/ui-mcp-per-user-oauth-llm-prompt-mcp.pngis excluded by!**/*.pngdocs/media/ui-mcp-per-user-oauth-setup.pngis excluded by!**/*.png
📒 Files selected for processing (11)
docs/changelogs/v1.5.0-prerelease2.mdxdocs/docs.jsondocs/mcp/connecting-to-servers.mdxdocs/mcp/gateway-url.mdxdocs/mcp/oauth.mdxdocs/mcp/overview.mdxdocs/mcp/per-user-oauth.mdxdocs/openapi/openapi.jsondocs/openapi/openapi.yamldocs/openapi/paths/management/oauth.yamldocs/openapi/schemas/management/oauth.yaml
Merge activity
|
## Summary
Adds comprehensive per-user OAuth 2.1 support for MCP clients, enabling each end-user to authenticate with upstream services (Notion, GitHub, etc.) using their own credentials instead of shared admin tokens. Also introduces a unified model alias system to map model names to provider-specific identifiers.
## Changes
- **Per-User OAuth Implementation**: Complete OAuth 2.1 authorization server with dynamic client registration (RFC 7591), PKCE support (RFC 7636), and OAuth discovery (RFC 8414, RFC 9728)
- **Consent Flow**: Multi-step browser-based consent system allowing users to select identity (Virtual Key, User ID, or session-only) and connect upstream services
- **Cross-Gateway Token Sharing**: Tokens stored against persistent identities work across both MCP Gateway and LLM Gateway
- **Lazy Authentication**: Runtime auth for services skipped during consent, with auth URLs returned in tool results
- **Model Alias System**: Unified top-level `aliases` field replacing provider-specific `deployments` configurations
- **Breaking Changes**: Provider `deployments` removed, Go SDK field renames for model tracking
- **Documentation**: Comprehensive guides for per-user OAuth setup, flows, and migration
## Type of change
- [x] Feature
- [ ] Bug fix
- [ ] Refactor
- [x] Documentation
- [ ] Chore/CI
## Affected areas
- [x] Core (Go)
- [x] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [x] UI (Next.js)
- [x] Docs
## How to test
### Per-User OAuth Flow
```sh
# 1. Configure an MCP client with per_user_oauth via Web UI
# 2. Test MCP client connection (Claude Code, Cursor)
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-d '{"method": "tools/list"}'
# Should return 401 with WWW-Authenticate header
# 3. Test OAuth discovery
curl http://localhost:8080/.well-known/oauth-protected-resource
curl http://localhost:8080/.well-known/oauth-authorization-server
# 4. Test dynamic client registration
curl -X POST http://localhost:8080/api/oauth/per-user/register \
-H "Content-Type: application/json" \
-d '{"client_name":"Test","redirect_uris":["http://localhost:3000/callback"]}'
```
### Model Aliases
```sh
# Test alias resolution in chat completions
curl -X POST http://localhost:8080/v1/chat/completions \
-H "Authorization: Bearer vk_your_key" \
-H "Content-Type: application/json" \
-d '{"model":"my-custom-alias","messages":[{"role":"user","content":"test"}]}'
```
### Core/Transports
```sh
go version
go test ./...
```
### UI
```sh
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```
## Screenshots/Recordings
- Identity selection screen for consent flow
- MCP services connection interface
- Per-user OAuth setup in Web UI
- Auth URL presentation in Claude Code and LLM responses
## Breaking changes
- [x] Yes
- [ ] No
**Breaking Changes in v1.5.0-prerelease2:**
1. **Provider `deployments` removed** - Azure, Bedrock, Vertex, and Replicate deployment maps must migrate to the unified top-level `aliases` field
2. **Go SDK: `ExtraFields.ModelRequested`** replaced by `OriginalModelRequested` + `ResolvedModelUsed`
3. **Go SDK: `StreamAccumulatorResult.Model`** replaced by `RequestedModel` + `ResolvedModel`
See the [v1.5.0 Migration Guide](/migration-guides/v1.5.0) for full before/after examples and automatic migration details.
## Related issues
Implements per-user OAuth authentication for MCP clients and introduces unified model aliasing system.
## Security considerations
- **PKCE Required**: All OAuth flows require PKCE with S256 method for security
- **Browser Binding**: HttpOnly SameSite=Lax cookies prevent CSRF attacks during consent flows
- **Token Isolation**: Per-user tokens are scoped to individual identities with no cross-user access
- **Session Management**: 24-hour session tokens with automatic cleanup of expired flows/codes
- **Identity Validation**: Virtual Keys validated against database; User IDs are self-declared following existing trust model
## Checklist
- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [x] I verified the CI pipeline passes locally if applicable

Summary
Adds comprehensive per-user OAuth 2.1 support for MCP clients, enabling each end-user to authenticate with upstream services (Notion, GitHub, etc.) using their own credentials instead of shared admin tokens. Also introduces a unified model alias system to map model names to provider-specific identifiers.
Changes
aliasesfield replacing provider-specificdeploymentsconfigurationsdeploymentsremoved, Go SDK field renames for model trackingType of change
Affected areas
How to test
Per-User OAuth Flow
Model Aliases
Core/Transports
go version go test ./...UI
Screenshots/Recordings
Breaking changes
Breaking Changes in v1.5.0-prerelease2:
deploymentsremoved - Azure, Bedrock, Vertex, and Replicate deployment maps must migrate to the unified top-levelaliasesfieldExtraFields.ModelRequestedreplaced byOriginalModelRequested+ResolvedModelUsedStreamAccumulatorResult.Modelreplaced byRequestedModel+ResolvedModelSee the v1.5.0 Migration Guide for full before/after examples and automatic migration details.
Related issues
Implements per-user OAuth authentication for MCP clients and introduces unified model aliasing system.
Security considerations
Checklist
docs/contributing/README.mdand followed the guidelines