first commit
This commit is contained in:
769
docs/openapi/paths/management/oauth.yaml
Normal file
769
docs/openapi/paths/management/oauth.yaml
Normal file
@@ -0,0 +1,769 @@
|
||||
oauth-callback:
|
||||
get:
|
||||
operationId: handleOAuthCallback
|
||||
summary: OAuth callback endpoint
|
||||
description: |
|
||||
Handles the OAuth provider callback after user authorization.
|
||||
This endpoint processes the authorization code and exchanges it for an access token.
|
||||
On success, displays an HTML page that closes the authorization window.
|
||||
tags:
|
||||
- OAuth
|
||||
parameters:
|
||||
- name: state
|
||||
in: query
|
||||
required: true
|
||||
description: State parameter for OAuth security (CSRF protection)
|
||||
schema:
|
||||
type: string
|
||||
- name: code
|
||||
in: query
|
||||
required: true
|
||||
description: Authorization code from the OAuth provider
|
||||
schema:
|
||||
type: string
|
||||
- name: error
|
||||
in: query
|
||||
required: false
|
||||
description: Error code if authorization failed
|
||||
schema:
|
||||
type: string
|
||||
- name: error_description
|
||||
in: query
|
||||
required: false
|
||||
description: Error description if authorization failed
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: OAuth authorization successful. Returns HTML page that closes the authorization window.
|
||||
content:
|
||||
text/html:
|
||||
schema:
|
||||
type: string
|
||||
'400':
|
||||
description: OAuth authorization failed or missing required parameters
|
||||
content:
|
||||
text/html:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
oauth-config-status:
|
||||
get:
|
||||
operationId: getOAuthConfigStatus
|
||||
summary: Get OAuth config status
|
||||
description: |
|
||||
Retrieves the current status of an OAuth configuration.
|
||||
Shows whether the OAuth flow is pending, authorized, or failed,
|
||||
and includes token expiration and scopes if authorized.
|
||||
tags:
|
||||
- OAuth
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
description: OAuth config ID
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: OAuth config status retrieved successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '../../schemas/management/oauth.yaml#/OAuthConfigStatus'
|
||||
'404':
|
||||
description: OAuth config not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '../../schemas/management/common.yaml#/ErrorResponse'
|
||||
'500':
|
||||
$ref: '../../openapi.yaml#/components/responses/InternalError'
|
||||
|
||||
delete:
|
||||
operationId: revokeOAuthConfig
|
||||
summary: Revoke OAuth config
|
||||
description: |
|
||||
Revokes an OAuth configuration and its associated access token.
|
||||
After revocation, the MCP client will no longer be able to use this OAuth token.
|
||||
tags:
|
||||
- OAuth
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
description: OAuth config ID
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: OAuth token revoked successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '../../schemas/management/common.yaml#/SuccessResponse'
|
||||
'500':
|
||||
$ref: '../../openapi.yaml#/components/responses/InternalError'
|
||||
|
||||
# ─── Per-User OAuth 2.1 Authorization Server ───────────────────────────────
|
||||
# These endpoints implement RFC 7591 (dynamic registration), RFC 7636 (PKCE),
|
||||
# and the OAuth 2.1 authorization code flow. MCP clients use them automatically
|
||||
# when connecting to Bifrost's /mcp endpoint. Only active when at least one MCP
|
||||
# client is configured with auth_type: per_user_oauth.
|
||||
|
||||
per-user-oauth-register:
|
||||
post:
|
||||
operationId: registerPerUserOAuthClient
|
||||
summary: Register OAuth client (RFC 7591)
|
||||
description: |
|
||||
Dynamic Client Registration per RFC 7591. MCP clients (Claude Code, Cursor, etc.)
|
||||
call this endpoint to obtain a `client_id` before initiating the authorization flow.
|
||||
|
||||
This endpoint is only available when at least one MCP client is configured with
|
||||
`auth_type: per_user_oauth`. Returns `404` otherwise.
|
||||
|
||||
Authentication is not required — this is part of the unauthenticated OAuth bootstrap flow.
|
||||
tags:
|
||||
- OAuth
|
||||
- Per-User OAuth
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '../../schemas/management/oauth.yaml#/PerUserOAuthClientRegistrationRequest'
|
||||
example:
|
||||
client_name: "Claude Code"
|
||||
redirect_uris: ["http://localhost:54321/callback"]
|
||||
grant_types: ["authorization_code"]
|
||||
response_types: ["code"]
|
||||
token_endpoint_auth_method: "none"
|
||||
responses:
|
||||
'201':
|
||||
description: Client registered successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '../../schemas/management/oauth.yaml#/PerUserOAuthClientRegistrationResponse'
|
||||
example:
|
||||
client_id: "550e8400-e29b-41d4-a716-446655440000"
|
||||
client_name: "Claude Code"
|
||||
redirect_uris: ["http://localhost:54321/callback"]
|
||||
grant_types: ["authorization_code"]
|
||||
token_endpoint_auth_method: "none"
|
||||
'400':
|
||||
$ref: '../../openapi.yaml#/components/responses/BadRequest'
|
||||
'404':
|
||||
description: No per-user OAuth MCP clients configured
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
'503':
|
||||
description: Config store is disabled
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '../../schemas/management/common.yaml#/ErrorResponse'
|
||||
|
||||
per-user-oauth-authorize:
|
||||
get:
|
||||
operationId: authorizePerUserOAuth
|
||||
summary: Authorization endpoint (OAuth 2.1)
|
||||
description: |
|
||||
OAuth 2.1 authorization endpoint. Validates the request parameters, creates a
|
||||
browser-bound `PendingFlow` record (15-minute TTL), and redirects the user to
|
||||
the Bifrost consent screen at `/oauth/consent?flow_id=xxx`.
|
||||
|
||||
**PKCE is required** — `code_challenge` and `code_challenge_method=S256` must
|
||||
be provided. Plain code challenges are not supported.
|
||||
|
||||
A `__bifrost_flow_secret` HttpOnly SameSite=Lax cookie is set on redirect to
|
||||
bind the consent flow to the initiating browser session (CSRF protection).
|
||||
|
||||
Authentication is not required — this is part of the unauthenticated OAuth bootstrap flow.
|
||||
tags:
|
||||
- OAuth
|
||||
- Per-User OAuth
|
||||
parameters:
|
||||
- name: response_type
|
||||
in: query
|
||||
required: true
|
||||
description: Must be `code`
|
||||
schema:
|
||||
type: string
|
||||
enum: [code]
|
||||
- name: client_id
|
||||
in: query
|
||||
required: true
|
||||
description: Client ID obtained from the registration endpoint
|
||||
schema:
|
||||
type: string
|
||||
- name: redirect_uri
|
||||
in: query
|
||||
required: true
|
||||
description: Must match a URI registered for this client
|
||||
schema:
|
||||
type: string
|
||||
- name: code_challenge
|
||||
in: query
|
||||
required: true
|
||||
description: PKCE code challenge (Base64URL-encoded SHA-256 of the code verifier)
|
||||
schema:
|
||||
type: string
|
||||
- name: code_challenge_method
|
||||
in: query
|
||||
required: true
|
||||
description: Must be `S256`
|
||||
schema:
|
||||
type: string
|
||||
enum: [S256]
|
||||
- name: state
|
||||
in: query
|
||||
required: false
|
||||
description: Opaque value to maintain state between request and callback (CSRF protection)
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'302':
|
||||
description: Redirect to consent screen at `/oauth/consent?flow_id=xxx`
|
||||
headers:
|
||||
Location:
|
||||
schema:
|
||||
type: string
|
||||
description: URL of the consent screen
|
||||
Set-Cookie:
|
||||
schema:
|
||||
type: string
|
||||
description: "`__bifrost_flow_secret` HttpOnly SameSite=Lax cookie for browser binding"
|
||||
'400':
|
||||
$ref: '../../openapi.yaml#/components/responses/BadRequest'
|
||||
'404':
|
||||
description: No per-user OAuth MCP clients configured, or unknown client_id
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
'503':
|
||||
description: Config store is disabled
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '../../schemas/management/common.yaml#/ErrorResponse'
|
||||
|
||||
per-user-oauth-token:
|
||||
post:
|
||||
operationId: exchangePerUserOAuthToken
|
||||
summary: Token endpoint (OAuth 2.1)
|
||||
description: |
|
||||
OAuth 2.1 token endpoint. Exchanges a single-use authorization code (5-minute TTL)
|
||||
for a Bifrost-issued access token (24-hour TTL) using PKCE verification.
|
||||
|
||||
The request body must be `application/x-www-form-urlencoded`.
|
||||
|
||||
The returned `access_token` is the Bearer token to use on subsequent `/mcp` requests.
|
||||
It carries the user's upstream service tokens (Notion, GitHub, etc.) linked to their
|
||||
identity (Virtual Key or User ID) from the consent flow.
|
||||
|
||||
Authentication is not required — this is part of the unauthenticated OAuth bootstrap flow.
|
||||
tags:
|
||||
- OAuth
|
||||
- Per-User OAuth
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/x-www-form-urlencoded:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- grant_type
|
||||
- code
|
||||
- code_verifier
|
||||
properties:
|
||||
grant_type:
|
||||
type: string
|
||||
description: Must be `authorization_code`
|
||||
enum: [authorization_code]
|
||||
code:
|
||||
type: string
|
||||
description: Authorization code received in the redirect callback
|
||||
redirect_uri:
|
||||
type: string
|
||||
description: Must match the redirect_uri used in the authorize request (if provided)
|
||||
client_id:
|
||||
type: string
|
||||
description: Client ID (optional — code is already bound to the client)
|
||||
code_verifier:
|
||||
type: string
|
||||
description: PKCE code verifier — the raw secret whose SHA-256 matches the code_challenge
|
||||
responses:
|
||||
'200':
|
||||
description: Token issued successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '../../schemas/management/oauth.yaml#/PerUserOAuthTokenResponse'
|
||||
example:
|
||||
access_token: "abc123xyz..."
|
||||
token_type: "Bearer"
|
||||
expires_in: 86400
|
||||
scope: "mcp:read mcp:write"
|
||||
'400':
|
||||
description: Invalid grant, expired code, PKCE failure, or unsupported grant type
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
enum: [invalid_grant, invalid_request, unsupported_grant_type]
|
||||
error_description:
|
||||
type: string
|
||||
'404':
|
||||
description: No per-user OAuth MCP clients configured
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
'500':
|
||||
description: Server error or session creation failed
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
enum: [server_error]
|
||||
error_description:
|
||||
type: string
|
||||
|
||||
per-user-oauth-upstream-authorize:
|
||||
get:
|
||||
operationId: authorizeUpstreamPerUserOAuth
|
||||
summary: Upstream OAuth proxy — authorize with upstream service
|
||||
description: |
|
||||
Initiates an OAuth flow with an upstream MCP service (Notion, GitHub, etc.)
|
||||
on behalf of the current user. Used during the consent flow (via "Connect" buttons
|
||||
on the MCPs page) and at runtime when a tool call is made to an unauthenticated service.
|
||||
|
||||
**Consent flow** — provide `flow_id` (from the pending consent flow). The browser-binding
|
||||
cookie (`__bifrost_flow_secret`) is validated.
|
||||
|
||||
**Runtime flow** — provide `session` (the Bifrost session ID from the token endpoint).
|
||||
Used when a service was skipped during consent and needs to be connected later.
|
||||
|
||||
On success, redirects the user to the upstream provider's authorize URL. After the user
|
||||
grants access, the upstream callback lands at `/api/oauth/callback`, stores the upstream
|
||||
token against the user's identity, and redirects back to the consent screen (consent flow)
|
||||
or returns an authorization success page (runtime flow).
|
||||
|
||||
Authentication is not required — cookie/session validation is performed instead.
|
||||
tags:
|
||||
- OAuth
|
||||
- Per-User OAuth
|
||||
parameters:
|
||||
- name: mcp_client_id
|
||||
in: query
|
||||
required: true
|
||||
description: ID of the per-user OAuth MCP client to authenticate with
|
||||
schema:
|
||||
type: string
|
||||
- name: flow_id
|
||||
in: query
|
||||
required: false
|
||||
description: |
|
||||
Pending consent flow ID. Required if `session` is not provided.
|
||||
The `__bifrost_flow_secret` cookie must be present and match the flow.
|
||||
schema:
|
||||
type: string
|
||||
- name: session
|
||||
in: query
|
||||
required: false
|
||||
description: |
|
||||
Bifrost session ID (from the token endpoint). Required if `flow_id` is not provided.
|
||||
Used for runtime (post-consent) upstream authorization.
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'302':
|
||||
description: Redirect to upstream OAuth provider's authorize URL
|
||||
headers:
|
||||
Location:
|
||||
schema:
|
||||
type: string
|
||||
description: Upstream provider authorization URL with PKCE parameters
|
||||
'400':
|
||||
$ref: '../../openapi.yaml#/components/responses/BadRequest'
|
||||
'401':
|
||||
description: Invalid or expired flow/session
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '../../schemas/management/common.yaml#/ErrorResponse'
|
||||
'403':
|
||||
description: Browser-binding cookie mismatch (CSRF protection)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '../../schemas/management/common.yaml#/ErrorResponse'
|
||||
'404':
|
||||
description: MCP client not found or not configured for per-user OAuth
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '../../schemas/management/common.yaml#/ErrorResponse'
|
||||
'503':
|
||||
description: Config store is disabled
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '../../schemas/management/common.yaml#/ErrorResponse'
|
||||
|
||||
# ─── Per-User OAuth Consent Flow (browser UI) ──────────────────────────────
|
||||
# These endpoints serve HTML pages and handle form submissions for the
|
||||
# multi-step consent flow. They are browser-facing, not JSON API endpoints.
|
||||
# All endpoints validate the __bifrost_flow_secret browser-binding cookie.
|
||||
|
||||
consent-identity-page:
|
||||
get:
|
||||
operationId: getConsentIdentityPage
|
||||
summary: Consent identity selection page
|
||||
description: |
|
||||
Renders the identity selection screen where the user chooses how to identify
|
||||
themselves for the session: Virtual Key, User ID, or Skip (session-only auth).
|
||||
|
||||
The `__bifrost_flow_secret` HttpOnly cookie set during `/api/oauth/per-user/authorize`
|
||||
must be present — it binds the consent flow to the initiating browser.
|
||||
|
||||
The Skip option is only shown when `enforce_auth_on_inference` is `false` in config.
|
||||
tags:
|
||||
- Per-User OAuth
|
||||
- Consent Flow
|
||||
parameters:
|
||||
- name: flow_id
|
||||
in: query
|
||||
required: true
|
||||
description: Pending flow ID from the authorize redirect
|
||||
schema:
|
||||
type: string
|
||||
- name: error
|
||||
in: query
|
||||
required: false
|
||||
description: Error message to display (used on redirect-back from failed form submissions)
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: Identity selection HTML page
|
||||
content:
|
||||
text/html:
|
||||
schema:
|
||||
type: string
|
||||
'400':
|
||||
description: Missing or expired flow_id
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
'403':
|
||||
description: Browser-binding cookie mismatch
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
consent-mcps-page:
|
||||
get:
|
||||
operationId: getConsentMCPsPage
|
||||
summary: Consent MCP services page
|
||||
description: |
|
||||
Renders the MCP services connection screen. Shows all per-user OAuth MCP servers
|
||||
available on the user's Virtual Key (or all servers if no VK was selected).
|
||||
Each service shows a "Connect" link or a "Connected ✓" badge.
|
||||
|
||||
Requires the `__bifrost_flow_secret` browser-binding cookie.
|
||||
tags:
|
||||
- Per-User OAuth
|
||||
- Consent Flow
|
||||
parameters:
|
||||
- name: flow_id
|
||||
in: query
|
||||
required: true
|
||||
description: Pending flow ID
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: MCP services connection HTML page
|
||||
content:
|
||||
text/html:
|
||||
schema:
|
||||
type: string
|
||||
'400':
|
||||
description: Missing or expired flow_id
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
'403':
|
||||
description: Browser-binding cookie mismatch
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
consent-submit-vk:
|
||||
post:
|
||||
operationId: submitConsentVirtualKey
|
||||
summary: Submit Virtual Key identity
|
||||
description: |
|
||||
Validates the submitted Virtual Key and links it to the pending flow as the user's
|
||||
identity. On success, redirects to the MCPs page. On failure, redirects back to the
|
||||
identity page with an error message.
|
||||
|
||||
Request body is `application/x-www-form-urlencoded` (browser form submission).
|
||||
tags:
|
||||
- Per-User OAuth
|
||||
- Consent Flow
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/x-www-form-urlencoded:
|
||||
schema:
|
||||
type: object
|
||||
required: [flow_id, vk]
|
||||
properties:
|
||||
flow_id:
|
||||
type: string
|
||||
description: Pending flow ID
|
||||
vk:
|
||||
type: string
|
||||
description: Virtual Key value (validated against the database)
|
||||
responses:
|
||||
'302':
|
||||
description: |
|
||||
Redirect to `/oauth/consent/mcps?flow_id=xxx` on success, or back to
|
||||
`/oauth/consent?flow_id=xxx&error=...` on failure.
|
||||
headers:
|
||||
Location:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
consent-submit-user-id:
|
||||
post:
|
||||
operationId: submitConsentUserID
|
||||
summary: Submit User ID identity
|
||||
description: |
|
||||
Links a self-declared User ID to the pending flow as the user's identity.
|
||||
On success, redirects to the MCPs page.
|
||||
|
||||
The User ID is self-declared with no server-side verification — it matches
|
||||
the trust model of the `X-Bf-User-Id` header in the LLM Gateway path.
|
||||
|
||||
Request body is `application/x-www-form-urlencoded` (browser form submission).
|
||||
tags:
|
||||
- Per-User OAuth
|
||||
- Consent Flow
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/x-www-form-urlencoded:
|
||||
schema:
|
||||
type: object
|
||||
required: [flow_id, user_id]
|
||||
properties:
|
||||
flow_id:
|
||||
type: string
|
||||
description: Pending flow ID
|
||||
user_id:
|
||||
type: string
|
||||
description: Self-declared user identifier (max 255 characters)
|
||||
responses:
|
||||
'302':
|
||||
description: |
|
||||
Redirect to `/oauth/consent/mcps?flow_id=xxx` on success, or back to
|
||||
`/oauth/consent?flow_id=xxx&error=...` on failure.
|
||||
headers:
|
||||
Location:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
consent-skip:
|
||||
post:
|
||||
operationId: skipConsentIdentity
|
||||
summary: Skip identity selection
|
||||
description: |
|
||||
Skips identity selection and proceeds directly to the MCPs page. Upstream service
|
||||
tokens will be stored against the session token only (not a persistent identity),
|
||||
so they will not carry over to other sessions or the LLM Gateway.
|
||||
|
||||
Only available when `enforce_auth_on_inference` is `false` in config. Returns a
|
||||
redirect back to the identity page with an error if auth enforcement is enabled.
|
||||
|
||||
Request body is `application/x-www-form-urlencoded` (browser form submission).
|
||||
tags:
|
||||
- Per-User OAuth
|
||||
- Consent Flow
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/x-www-form-urlencoded:
|
||||
schema:
|
||||
type: object
|
||||
required: [flow_id]
|
||||
properties:
|
||||
flow_id:
|
||||
type: string
|
||||
description: Pending flow ID
|
||||
responses:
|
||||
'302':
|
||||
description: |
|
||||
Redirect to `/oauth/consent/mcps?flow_id=xxx` on success, or back to
|
||||
`/oauth/consent?flow_id=xxx&error=...` if identity enforcement is required.
|
||||
headers:
|
||||
Location:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
consent-submit:
|
||||
post:
|
||||
operationId: submitConsent
|
||||
summary: Finalize consent flow
|
||||
description: |
|
||||
Finalizes the consent flow atomically:
|
||||
1. Creates a `TablePerUserOAuthSession` (24h Bifrost session token)
|
||||
2. Transfers upstream tokens from the flow proxy to the session
|
||||
3. Issues a single-use `TablePerUserOAuthCode` (5-minute TTL, PKCE-bound)
|
||||
4. Deletes the `PendingFlow`
|
||||
5. Redirects to the MCP client's `redirect_uri` with `code` and `state`
|
||||
|
||||
The MCP client then exchanges the code at `/api/oauth/per-user/token`.
|
||||
|
||||
Request body is `application/x-www-form-urlencoded` (browser form submission).
|
||||
tags:
|
||||
- Per-User OAuth
|
||||
- Consent Flow
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/x-www-form-urlencoded:
|
||||
schema:
|
||||
type: object
|
||||
required: [flow_id]
|
||||
properties:
|
||||
flow_id:
|
||||
type: string
|
||||
description: Pending flow ID
|
||||
responses:
|
||||
'302':
|
||||
description: |
|
||||
Redirect to the MCP client's registered `redirect_uri` with
|
||||
`?code=xxx&state=yyy` query parameters.
|
||||
headers:
|
||||
Location:
|
||||
schema:
|
||||
type: string
|
||||
description: MCP client callback URL with code and state
|
||||
'400':
|
||||
$ref: '../../openapi.yaml#/components/responses/BadRequest'
|
||||
'403':
|
||||
description: Browser-binding cookie mismatch
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '../../schemas/management/common.yaml#/ErrorResponse'
|
||||
'409':
|
||||
description: Consent flow already submitted (duplicate submission prevention)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '../../schemas/management/common.yaml#/ErrorResponse'
|
||||
'410':
|
||||
description: Consent flow expired
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '../../schemas/management/common.yaml#/ErrorResponse'
|
||||
'500':
|
||||
$ref: '../../openapi.yaml#/components/responses/InternalError'
|
||||
|
||||
# ─── OAuth Discovery (RFC 9728 + RFC 8414) ─────────────────────────────────
|
||||
# These well-known endpoints enable MCP clients to auto-discover Bifrost's
|
||||
# OAuth configuration. Only active when at least one MCP client is configured
|
||||
# with auth_type: per_user_oauth.
|
||||
|
||||
oauth-protected-resource-metadata:
|
||||
get:
|
||||
operationId: getOAuthProtectedResourceMetadata
|
||||
summary: Protected Resource Metadata (RFC 9728)
|
||||
description: |
|
||||
Returns the OAuth 2.0 Protected Resource Metadata document per RFC 9728.
|
||||
|
||||
MCP clients fetch this after receiving a `401` response from `/mcp` (with a
|
||||
`WWW-Authenticate: Bearer resource_metadata=".../.well-known/oauth-protected-resource"`
|
||||
header). The response tells the client which authorization server(s) protect the
|
||||
`/mcp` resource so it can proceed with discovery.
|
||||
|
||||
Returns `404` when no MCP clients are configured with `auth_type: per_user_oauth`.
|
||||
tags:
|
||||
- OAuth
|
||||
- Per-User OAuth
|
||||
responses:
|
||||
'200':
|
||||
description: Protected resource metadata
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '../../schemas/management/oauth.yaml#/ProtectedResourceMetadata'
|
||||
example:
|
||||
resource: "https://your-bifrost-domain.com/mcp"
|
||||
authorization_servers: ["https://your-bifrost-domain.com"]
|
||||
scopes_supported: ["mcp:read", "mcp:write"]
|
||||
bearer_methods_supported: ["header"]
|
||||
'404':
|
||||
description: No per-user OAuth MCP clients configured
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
oauth-authorization-server-metadata:
|
||||
get:
|
||||
operationId: getOAuthAuthorizationServerMetadata
|
||||
summary: Authorization Server Metadata (RFC 8414)
|
||||
description: |
|
||||
Returns the OAuth 2.0 Authorization Server Metadata document per RFC 8414.
|
||||
|
||||
After fetching the Protected Resource Metadata, MCP clients fetch this endpoint
|
||||
to discover Bifrost's OAuth endpoints (register, authorize, token) and capabilities
|
||||
(PKCE methods, grant types, etc.).
|
||||
|
||||
Returns `404` when no MCP clients are configured with `auth_type: per_user_oauth`.
|
||||
tags:
|
||||
- OAuth
|
||||
- Per-User OAuth
|
||||
responses:
|
||||
'200':
|
||||
description: Authorization server metadata
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '../../schemas/management/oauth.yaml#/AuthorizationServerMetadata'
|
||||
example:
|
||||
issuer: "https://your-bifrost-domain.com"
|
||||
authorization_endpoint: "https://your-bifrost-domain.com/api/oauth/per-user/authorize"
|
||||
token_endpoint: "https://your-bifrost-domain.com/api/oauth/per-user/token"
|
||||
registration_endpoint: "https://your-bifrost-domain.com/api/oauth/per-user/register"
|
||||
response_types_supported: ["code"]
|
||||
grant_types_supported: ["authorization_code"]
|
||||
code_challenge_methods_supported: ["S256"]
|
||||
token_endpoint_auth_methods_supported: ["none"]
|
||||
scopes_supported: ["mcp:read", "mcp:write"]
|
||||
'404':
|
||||
description: No per-user OAuth MCP clients configured
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
Reference in New Issue
Block a user