> For the complete documentation index, see [llms.txt](https://docs.flowcp.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.flowcp.ai/security/user-context-oauth.md).

# User-context OAuth

Every MCP tool call in FlowCP runs under the OAuth token of the specific end user making the request — issued by your API's own OAuth provider, not a shared admin or service account token.

## Why this matters

Most API integrations use a single admin token to act on behalf of all users. This creates problems:

* **Overprivileged access.** An admin token typically has access to all user data. A bug or misconfiguration exposes data it should not.
* **No audit trail.** Your API's logs show the admin user, not the actual end user who triggered the action.
* **Privacy violations.** One user can inadvertently access another user's data if the integration is not carefully scoped.

FlowCP's user-context model avoids all of these. Each request carries the calling user's own token. Your API enforces its own privacy rules and permission scopes as normal — FlowCP is a transparent proxy.

## How it works

FlowCP uses a **stateless OAuth proxy** model. Tokens are never stored on FlowCP's servers — the AI client holds the access token and presents it on every request.

1. **First call.** When an end user's AI client connects to FlowCP, it has no token yet. FlowCP returns an OAuth challenge (`WWW-Authenticate` header). The AI client automatically initiates the OAuth authorization flow.
2. **Authorization.** FlowCP redirects the user to your provider's authorization page. The user logs in and grants access.
3. **Token handoff.** Your provider redirects back to FlowCP with an authorization code. FlowCP exchanges it for tokens, packages them in a short-lived encrypted auth code, and redirects the AI client back. The AI client completes the PKCE exchange and receives the access token directly.
4. **Token use.** On every tool call, the AI client sends its access token as a `Bearer` header. FlowCP validates and forwards it to your API — no database lookup required.
5. **Re-authorization.** When the token expires, your API returns 401. FlowCP propagates this as an HTTP 401 with a `WWW-Authenticate` header. Compliant AI clients automatically restart the OAuth flow to obtain a fresh token.
6. **Fail closed.** If the AI client presents an invalid or expired token and does not re-authorize, tool calls are rejected. FlowCP never falls back to an admin token.

## What FlowCP never does

* Stores access tokens or refresh tokens in its database
* Uses a shared admin or service account token for user requests
* Falls back to any other credential when a user's token is unavailable
* Logs access tokens or Authorization headers
* Allows one workspace's users to see another workspace's connections

## The Playground uses the same flow

The [Playground](/guides/chat-test-your-mcp-server.md) is just another OAuth client. When you click **Connect account**, it runs the exact same stateless proxy flow described above — so testing in the Playground also validates your OAuth configuration. The resulting token lives only in your browser for that session and is never persisted, just like a real AI client's token.

## Revoking access

Users can revoke FlowCP's access from their account with your provider (for Bubble, Settings → Connected apps). Once revoked, the next tool call will fail and the AI client will prompt the user to re-authorize.

## When user-context applies

User-context OAuth is the default and recommended mode, and everything above applies whenever a branch's [Authentication](/guides/configure-oauth.md#authentication-modes) is set to **User OAuth**.

For APIs that don't offer per-user OAuth, a branch can instead use a **shared-credential** mode — **API key**, **Static bearer**, or **None**. These are a deliberate trade-off: a single workspace-configured credential (or no credential) is used for every end user, so the per-user guarantees above — per-user scoping, per-user audit attribution, and "never fall back to a shared credential" — **do not apply** to those branches. FlowCP still encrypts the static credential at rest, keeps it out of logs and caches, and enforces every other guardrail (default-deny tools, confirmation on destructive actions, rate limits, audit logging, and publish blockers). Choose a shared-credential mode only when user-context OAuth isn't an option.
