Documentation Index
Fetch the complete documentation index at: https://docs.getbifrost.ai/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Per-user headers is available in Bifrost v1.5.4 and above.
auth_type: "per_user_headers" lets each end-user supply their own HTTP headers for an upstream MCP server. The admin declares the header names that callers must fill in; each end-user submits their values the first time they hit the server. Bifrost stores one credential per (identity, mcp_client) and reuses it on every later call.
Use this when the upstream MCP server authenticates with per-user API keys, signed tokens, or any other static-shape credential — but does not offer OAuth (which would call for Per-User OAuth).
This auth type is only valid for HTTP and SSE connections.
Headers (headers) | Per-User Headers (per_user_headers) | |
|---|---|---|
| Who supplies values | Admin, once at setup | Each end-user, lazily |
| Where values live | MCP client config (encrypted) | Per-credential rows keyed by identity (encrypted) |
| Admin declares | Header names + values | Header names only (schema) |
| Identity required | No | Yes (VK, signed-in user, or session ID) |
How it works
The lazy-auth model is identical to Per-User OAuth — the only difference is what the user is asked for at the consent page:- Caller sends a request with an identity (header or SSO).
- The LLM (or MCP client) asks to invoke a tool on a
per_user_headersserver. - Bifrost looks up an existing credential for
(identity, mcp_client):- Found and
active→ Bifrost attaches the stored header values and calls upstream. - Missing,
orphaned, orneeds_update→ Bifrost returns anmcp_auth_requiredpayload with an inlinesubmit_url. The tool is not executed.
- Found and
- The user opens the URL, sees a Bifrost form listing the required header names, fills in values, and submits.
- Bifrost runs a one-time upstream verify with the submitted values, then stores the credential.
- The next request executes the tool normally.
mcp_auth_required payload carries kind: "headers" so SDKs can branch on it. The natural-language message also embeds the URL so plain-text clients see it:
#t=<temp-token> fragment when mcp_enable_temp_token_auth is turned on, letting anonymous browser visitors complete the form without a dashboard session (the fragment never reaches server logs). User-mode URLs never carry a temp token — visitors must complete SSO login first, and only the bound SSO user can finish the flow. See Flow mode and access rules.

Setup
The admin configures the MCP client once, declaring the schema (header names) end-users will need to fill in. During setup, Bifrost asks the admin for sample values, runs a one-time upstream verify, and discovers the tool list — same as the per-user OAuth setup pattern, just with a values form instead of an OAuth popup. Sample values are discarded after the test.- Web UI
- API
- config.json
- Navigate to MCP Gateway in the sidebar
- Click New MCP Server
- Pick HTTP or SSE as the connection type, fill in the Connection URL
- Set Auth Type to Per-User Headers
- Fill in Required Headers — comma-separated list of header names each caller must supply (e.g.
X-API-Key, X-Tenant-ID). Values are submitted per-user — never stored on this MCP config. - (Optional) Fill in Static Headers — admin-set headers that accompany every per-user request (e.g. a fixed tenant ID). These are visible to plugins; the per-user values aren’t.
- Click Create — a dialog opens asking for sample header values to run a one-time verify
- Enter sample values, click Run Test
- On success, the MCP client is persisted with the discovered tool list

Static admin headers
per_user_headers clients can carry both:
- Per-user values — what each end-user submits (e.g.,
X-API-Key,X-Tenant-ID) - Static admin headers — what the admin sets once and is sent on every per-user request (e.g.,
X-Region,X-Tenant-Class)
- Static admin headers are not allowed to override per-user header names. If
X-API-Keyappears in bothper_user_header_keysandheaders, the static value is dropped on the wire — the per-user value wins. Authorizationis treated as a credential by Bifrost and is never exposed to connect-plugins or accidentally leaked.- Static admin headers are visible to connect-plugins (so a plugin can read e.g.
X-Regionand mutate it); per-user values aren’t.
Editing the schema
If the admin later changesper_user_header_keys (adds, removes, or renames a required header), all existing credentials for that MCP server flip to needs_update. End-users will see an mcp_auth_required payload on the next tool call and be sent back to the submission form to fill in the new schema. Their old values are preserved where the key still matches — the form pre-shows which keys are already on file (names only, never values).
- Web UI
- API
- Open the MCP client in the MCP Gateway registry
- Click Edit
- Update Required Headers
- Click Save

needs_update. The next tool call from each user triggers a fresh submission.End-user submission flow
When an end-user hits the inline-401 URL, they land on/workspace/mcp-sessions/auth?flow=<id>&kind=headers:
- The page shows:
- Which MCP server is asking for values
- Which identity the resulting credential will be bound to (VK name, signed-in user, or session ID)
- One input per required header name
- Any static admin headers (names only) so the user knows what context their values will accompany
- The user fills in values and clicks Submit
- Bifrost runs a one-time upstream verify against the live MCP client config
- On success, the credential is persisted; the user sees a “Headers saved” confirmation and can close the tab
- On failure (bad key, upstream rejected), the page shows the error and offers Retry

Identity modes
Same model as Per-User OAuth —user > vk > session. A per-user-headers request with no identity is rejected with an inline-401 explaining the caller must send a VK, sign in, or set x-bf-mcp-session-id.
Cross-gateway sharing
Header credentials are stored against an identity, not a gateway. The same identity reaching either gateway reuses the credential. See Per-User OAuth — Cross-gateway sharing — the model is identical.Lifecycle and sessions
Every per-user header credential shows up on the MCP Sessions page with one of these statuses:| State | Badge | Meaning |
|---|---|---|
active | Active | Credential present and usable. Bifrost attaches the stored values on every call. |
needs_update | Needs update | Admin changed per_user_header_keys. Credential is preserved; user must resubmit to satisfy the new schema. |
orphaned | Orphaned | The caller’s VK lost access to this MCP (e.g. AP change). Credential preserved; auto-reactivates if access returns. |
Configuration reference
| Field | Type | Notes |
|---|---|---|
auth_type | string | "per_user_headers" |
per_user_header_keys | string[] | Required header names. Must be non-empty. |
headers | map[string]EnvVar | Optional static admin headers. |
user_headers | map[string]string | Create-only: admin sample values for the upstream verify; not persisted. |
MCP client names cannot contain hyphens — Bifrost prefixes tools as
<client>-<tool> and uses the hyphen to split the two halves at execution time.Troubleshooting
`Verification failed` on create
`Verification failed` on create
The admin sample values you supplied (
user_headers) didn’t pass upstream auth. Double-check the value spelling (some upstreams care about prefixes like Bearer or hex casing), then retry.End-users see `requires an identity` even though they sent a VK
End-users see `requires an identity` even though they sent a VK
The VK isn’t resolving. Confirm the VK exists and the caller is sending it under one of
x-bf-vk, Authorization: Bearer …, or x-api-key. If you’re behind a proxy that strips Authorization, switch the caller to x-bf-vk.`Headers submission flow has expired`
`Headers submission flow has expired`
Pending submission flows have a 15-minute TTL. Trigger the original action again to mint a fresh flow.
`Edit values` on the sessions page does nothing
`Edit values` on the sessions page does nothing
Make sure Bifrost can build a public URL — if behind a proxy, set
mcp_external_client_url so the redirect lands on the right host.Next Steps
- Per-User OAuth — when the upstream provides OAuth
- Headers — when one admin key fits everyone
- MCP Sessions — credential lifecycle, orphan/reactivate, revoke
- MCP Gateway Mode — expose Bifrost as an MCP server for Claude Code / Cursor

