> 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/guides/enterprise-managed-auth.md).

# Enterprise managed auth

> **Enterprise plan.** Managed auth is available on the Enterprise plan.

Managed auth makes **your own identity provider the authority** for who may reach an MCP server. Instead of every end user running their own OAuth consent flow — or everyone sharing one static credential — your IdP issues access tokens, FlowCP verifies each one before running anything, and the token's group memberships decide which tools that caller can use.

This is the mode to reach for when:

* Your organization already runs Okta, Microsoft Entra ID, Auth0, Keycloak, or any other OIDC provider, and you want MCP access governed there.
* Different teams should see different tools on the same server.
* Removing someone from a group in your IdP must remove their MCP access.

## How it compares

| Mode                 | Who the caller is                             | Who decides what they can do   |
| -------------------- | --------------------------------------------- | ------------------------------ |
| **User OAuth**       | Verified by your upstream API                 | Your API's own permissions     |
| **Managed auth**     | Verified by FlowCP against **your IdP**       | **Access rules** you configure |
| **API key / bearer** | Not identified — everyone shares one identity | Nothing per-user               |
| **None**             | Not identified                                | Nothing per-user               |

Managed auth authenticates the **caller**. The upstream API call still carries the server's **shared credential**, so you configure both: an identity provider (who may connect) and a shared auth config (how FlowCP talks to your API).

## 1. Add an identity provider

On the **MCP Auth** page for your app, find **Enterprise managed auth** and add a provider:

| Field             | What to enter                                                                                    |
| ----------------- | ------------------------------------------------------------------------------------------------ |
| **Name**          | A label, e.g. `Corporate IdP`. Defaults to `Default`.                                            |
| **Issuer URL**    | The exact `iss` claim your tokens carry, e.g. `https://login.microsoftonline.com/<tenant>/v2.0`. |
| **JWKS URL**      | Where your IdP publishes its signing keys.                                                       |
| **Audience**      | The `aud` claim your IdP mints for this MCP server, e.g. `api://flowcp-mcp`.                     |
| **Subject claim** | Claim carrying the stable user id. Defaults to `sub`.                                            |
| **Groups claim**  | Claim carrying group/role membership. Defaults to `groups`.                                      |

Both URLs must be public `https://` addresses — FlowCP fetches the JWKS server-side, so private and link-local addresses are rejected.

**Audience is not optional.** A token with no audience restriction can be replayed against every resource that trusts your issuer. Register this MCP server as its own API/resource in your IdP and put that identifier here.

### Provider notes

* **Microsoft Entra ID** — issuer is `https://login.microsoftonline.com/<tenant>/v2.0`, JWKS is `https://login.microsoftonline.com/<tenant>/discovery/v2.0/keys`. Entra emits `groups` as object IDs unless you configure group claims to emit names; use whichever your rules will match on.
* **Okta** — issuer is your authorization server (`https://<domain>/oauth2/<serverId>`), JWKS is that issuer plus `/v1/keys`. Add a `groups` claim to the access token.
* **Auth0** — issuer is `https://<tenant>/`, JWKS is `.../.well-known/jwks.json`. Groups usually arrive via a custom namespaced claim; set **Groups claim** to it.
* **Keycloak** — issuer is `https://<host>/realms/<realm>`, JWKS is that plus `/protocol/openid-connect/certs`.

## 2. Assign it to a branch

On the [Branches page](/guides/manage-branches.md), set a branch's **Authentication** to **Enterprise managed auth**, then pick the identity provider. A branch shows "Won't authenticate" until one is assigned.

You still need a shared auth config for the upstream call. If your API needs no credential, create a shared auth config with mode **None** and assign that.

## 3. Write access rules

Access rules map claims to tools. Each rule has:

* **Claim** — which claim to read, e.g. `groups`.
* **Operator** — `contains` (claim includes the value), `one_of` (claim overlaps any listed value), or `equals` (a single-valued claim equals it).
* **Values** — what to match.
* **Effect** — `allow` or `deny`.
* **Scope** — a single tool, or the whole server.

The rules resolve like this:

1. **A server with no rules allows everything.** Tools still have to be enabled.
2. **Deny wins over allow.** A blanket allow can't punch through a targeted deny.
3. **Otherwise a matching allow is required** — a server that has rules denies any caller none of them match. This is default deny, on purpose.

A worked example. Everyone in `mcp-users` may use the server; only `mcp-admins` may use `delete_customer`:

| Scope             | Claim    | Operator   | Values       | Effect |
| ----------------- | -------- | ---------- | ------------ | ------ |
| Whole server      | `groups` | `contains` | `mcp-users`  | allow  |
| `delete_customer` | `groups` | `contains` | `mcp-admins` | allow  |

Someone in `mcp-users` but not `mcp-admins` will not even **see** `delete_customer` — denied tools are hidden from the tool list, not just blocked when called. Resources backed by a hidden tool are hidden too.

## What the client sends

The MCP client presents your IdP's access token as a normal bearer token:

```http
POST /mcp/<serverId>
Authorization: Bearer <access token from your IdP>
```

A missing token, an expired one, a wrong audience, a wrong issuer, or a bad signature all return `401` with a `WWW-Authenticate` challenge. The response never says *which* check failed — that detail stays in FlowCP's server-side logs so the endpoint can't be used to probe your tokens.

## Revoking access

Removing a user from a group in your IdP takes effect as soon as they get a new token — their old one keeps its old claims until it expires, which is why short token lifetimes matter here. Deleting the identity provider config unassigns every branch using it, and those branches then refuse all traffic until you assign a new one.

## Audit

Every tool call from a managed server records the verified issuer and a **hash** of the caller's subject in the [execution log](/reference/execution-logs.md), so calls are attributable to a real corporate identity. The raw subject is never stored, and claims are never logged.

## Limits

* Managed auth needs the hosted runtime. [Self-hosted bundles](/guides/self-host-export.md) refuse the mode rather than starting up without the ability to verify callers.
* Tools that require an OAuth **scope** can't be published on a managed server — scopes describe a per-user OAuth token, and access rules replace them here.
* Tokens must be signed with `RS256` or `ES256`. Symmetric (`HS256`) and unsigned tokens are rejected.
