For the complete documentation index, see llms.txt. This page is also available as Markdown.

Configure MCP Auth

FlowCP authenticates end users with your API's OAuth 2.0 provider. This guide walks through setting up the OAuth provider configuration so your MCP server can act on behalf of real users.

An app can have multiple named OAuth configs, and you assign one config to each app branch on the Branches page. A config can serve many branches, but each branch uses exactly one config. This lets, for example, a staging branch point at a staging identity provider while the live branch uses production credentials.

Note: Changing an app's provider (for example, OpenAPI → Git) resets the app's OAuth configuration — credentials and URLs are provider-specific. After switching, set up OAuth again here and assign a config to each branch.

FlowCP supports OAuth for any provider, with first-class support for Bubble, Auth0, Clerk, Okta, Microsoft Entra ID, AWS Cognito, Keycloak, WorkOS (AuthKit), Zitadel, FusionAuth, Ory Hydra, Frontegg, Descope, Stytch, and Supabase, plus a Generic OAuth2 option for everything else. You pick a provider in each OAuth config; the rest of the setup (Client ID, Client Secret, redirect URI) is the same. Depending on the provider you supply a few provider-specific fields (see Provider-specific settings):

  • Bubble — FlowCP derives the authorize/token URLs from your Bubble app.

  • Auth0 — enter your Auth0 domain (tenant.auth0.com or a custom domain) and, optionally, an audience and organization.

  • Clerk — enter your Clerk domain (Frontend API).

  • Okta — enter your Okta domain and, optionally, a custom Authorization Server ID.

  • Microsoft Entra ID — enter your directory (tenant) ID.

  • AWS Cognito — enter your user pool region and User Pool ID (and, optionally, a Hosted UI domain).

  • Keycloak — enter your base URL and realm.

  • WorkOS (AuthKit), Zitadel, FusionAuth, Ory Hydra, Frontegg — enter the provider domain (FlowCP discovers the rest).

  • Descope — enter your project ID.

  • Stytch — enter your project ID and pick the environment (Live or Test).

  • Supabase — enter your project ref (the {ref}.supabase.co subdomain).

  • Generic OAuth2 — enter the authorize and token URLs directly.

Authentication modes

OAuth is the default and recommended mode, but not every API offers per-user OAuth. Each branch picks an Authentication mode on the Branches page:

Mode
How the upstream call is authenticated
Per-user context

User OAuth

The end user's own OAuth access token, forwarded on every call.

✅ Yes

Enterprise managed

A shared credential — but the caller is verified against your own identity provider first, and their group claims decide which tools they can use. See Enterprise managed auth.

✅ Yes (identity + per-tool rules)

API key

A shared static key you configure, sent as a header or query parameter.

❌ No

Static bearer

A shared static bearer token you configure.

❌ No

None

No credential is sent. All calls are unauthenticated.

❌ No

Shared-credential modes (API key, Static bearer, None) relax the per-user guarantee. Every end user acts through one identity, so FlowCP cannot scope calls to individual users or attribute audit-log entries to them. Use these modes only for APIs that have no per-user OAuth, and prefer User OAuth whenever it is available. See User-context OAuth.

The static key/token is encrypted at rest with AES-256-GCM, never returned after saving, never written to logs, and never cached. Switching a branch back to User OAuth clears any stored static credential.

You create configs for any of these modes on the MCP Auth page: click Add config and pick the auth type first (User OAuth, API key, Static bearer token, or No authentication). User OAuth opens the provider editor described below; the shared-credential modes open a short form for the credential and (for API key) its header/query placement. Each saved config can then be assigned to one or more branches on the Branches page. The rest of this guide covers User OAuth.

How the OAuth flow works

  1. An end user's AI client connects to FlowCP's MCP server.

  2. FlowCP checks whether the AI client has included a valid access token.

  3. If not, FlowCP returns an authorization challenge. The AI client redirects the user to FlowCP's OAuth endpoint.

  4. FlowCP redirects the user to your provider's authorization page.

  5. The user logs in with your provider and grants access.

  6. The provider redirects back to FlowCP with an authorization code.

  7. FlowCP exchanges the code for access and refresh tokens and returns them to the AI client as an encrypted auth code.

  8. The AI client holds the access token and presents it on every subsequent MCP tool call — FlowCP forwards it directly to your API.

  9. When the token expires, your API returns 401 and FlowCP signals the AI client to re-authorize automatically.

Step 1 — Enable OAuth with your provider

Set up an OAuth 2.0 client (sometimes called an "app" or "integration") with your API provider and note the Client ID, generate a Client Secret, and find the authorize and token endpoint URLs. Add the FlowCP redirect URI as an allowed redirect URL (see Step 2).

Bubble: Go to Settings → API, enable 3rd Party OAuth / SAML Access, note the Client ID, and generate a Client Secret. FlowCP derives the Bubble authorize/token URLs automatically, so you do not enter them by hand.

Step 2 — Get the FlowCP redirect URI

In the FlowCP dashboard, open your app and click MCP Auth in the sidebar.

The OAuth redirect URI field shows a read-only URL like:

Use the copy button next to the field to grab the URL, then paste it into your provider's allowed redirect URLs list.

Step 3 — Add an OAuth config

On the same MCP Auth page in FlowCP, click Add config, choose User OAuth as the auth type, and:

  1. Enter a Name to tell this config apart from others (e.g. “Production”, “Staging”).

  2. Choose your provider (Bubble, Auth0, Clerk, Okta, Microsoft Entra ID, AWS Cognito, Keycloak, WorkOS/AuthKit, Zitadel, FusionAuth, Ory Hydra, Frontegg, Descope, Stytch, Supabase, or Generic OAuth2).

  3. Enter the Client ID from your provider.

  4. Enter the Client Secret (treated as a write-only field — once saved, the value is not displayed again).

  5. Fill in the provider-specific fields below.

  6. Click Create config.

Repeat Add config for each distinct set of credentials you need. FlowCP encrypts each client secret at rest using AES-256-GCM.

The first config you add is assigned to every branch that doesn't yet have one. After that, assign configs to branches yourself on the Branches page.

The provider selector appears for apps connected via a Generic OpenAPI/Swagger URL, letting you choose Generic OAuth2, Auth0, Clerk, Okta, Microsoft Entra ID, or AWS Cognito. Apps connected as Bubble are fixed to the Bubble provider — there is no selector, and the authorize/token URLs are derived for you.

Step 4 — Assign configs to branches

Open Settings → Branches. Each branch has an Authentication dropdown. With User OAuth selected (the default), an OAuth config dropdown lists your configs — pick the one that branch should authenticate with. A branch left on None — not configured will not authenticate — its published MCP endpoint returns an error until you assign a config. To use a shared API key or bearer token instead, pick that mode and either assign an app-level config you created on the MCP Auth page or enter the credential inline (see Authentication modes).

See Managing branches for details.

Provider-specific settings

Provider
Required fields
Optional fields
Default scopes

Bubble

— (URLs derived)

scopes

Auth0

domain

audience, orgId (Organizations)

openid profile email

Clerk

domain

sameDomain (use the __session cookie)

openid profile email

Okta

domain

authServerId (custom Authorization Server), classic (Okta Classic / Org server)

openid profile email okta.users.read.self

Microsoft Entra ID

tenantId

scopes

openid profile email offline_access

AWS Cognito

region, userPoolId

domain (Hosted UI domain override), scopes

openid profile email

Keycloak

baseUrl, realm

scopes

openid profile email

WorkOS (AuthKit)

domain

scopes

openid profile email offline_access

Zitadel

domain

scopes

openid profile email offline_access

FusionAuth

domain

scopes

openid profile email offline_access

Ory Hydra

domain

scopes

openid profile email offline_access

Frontegg

domain

scopes

openid profile email

Descope

projectId

scopes

openid profile email

Stytch

projectId

environment (live / test), scopes

openid profile email

Supabase

projectRef

scopes

openid profile email

Generic OAuth2

authorizeUrl, tokenUrl

userInfoUrl, issuer, scopes

For every provider except Bubble and Generic OAuth2, FlowCP resolves the authorize, token, and userinfo endpoints automatically from the provider's OIDC discovery document, so you only enter a few identifiers:

  • Auth0 / Clerk / Okta / WorkOS (AuthKit) / Zitadel / FusionAuth / Ory Hydra / Frontegg — discovery runs against https://{domain}/.well-known/openid-configuration.

  • Microsoft Entra ID — discovery runs against the v2.0 endpoint https://login.microsoftonline.com/{tenantId}/v2.0/.well-known/openid-configuration. tenantId accepts a directory GUID, a verified domain, or one of common / organizations / consumers. The default scopes include offline_access, which Entra requires before it will issue a refresh token.

  • AWS Cognito — discovery runs against the user pool issuer https://cognito-idp.{region}.amazonaws.com/{userPoolId}, which advertises your Hosted UI endpoints. Set the optional Hosted UI domain only to override the resolved endpoints. Cognito app clients that have a secret authenticate to the token endpoint with HTTP Basic automatically.

  • Keycloak — discovery runs against the realm issuer {baseUrl}/realms/{realm}/.well-known/openid-configuration. Include an /auth path segment in baseUrl for legacy (≤16) deployments. Confidential clients authenticate to the token endpoint with HTTP Basic automatically.

  • Descope — discovery runs against https://api.descope.com/{projectId}. Your Descope project ID is also the OAuth client ID.

  • Stytch — discovery runs against https://{api|test}.stytch.com/v1/public/{projectId} (Connected Apps). Pick Live (api.stytch.com) or Test (test.stytch.com) with the environment field.

  • Supabase — discovery runs against https://{projectRef}.supabase.co/auth/v1/.well-known/openid-configuration (the Auth OAuth 2.1 server). Confidential clients authenticate to the token endpoint with HTTP Basic automatically.

Okta additionally validates the returned ID token's nonce to protect the login round trip.

For Generic OAuth2, the authorizeUrl and tokenUrl you enter are authoritative — FlowCP always uses them directly. The optional issuer is a fallback only: it is used to discover endpoints (via its /.well-known/openid-configuration) when you leave the explicit URLs blank, and is otherwise retained only as token metadata. It never overrides URLs you have entered.

Do not set issuer to FlowCP's own origin. Discovery against FlowCP resolves to its /oauth/authorize endpoint (the AI-client authorization server, not your upstream IdP) and creates a redirect loop that fails with unknown client_id. To use the FlowCP platform identity provider, set authorizeUrl to …/id/authorize and tokenUrl to …/id/token and leave issuer blank. FlowCP rejects a same-origin issuer (and same-origin /oauth/* authorize/token URLs) at save time.

Token refresh

FlowCP supports the OAuth2 refresh_token grant, so AI clients keep working without re-prompting the user. When an MCP client's access token nears expiry it silently exchanges its refresh token at the token endpoint; FlowCP resolves the server's provider and refreshes through it (for your own provider this requires that the provider issues refresh tokens — e.g. Auth0/Okta with offline_access). The refresh token FlowCP issues carries its own server context, so refresh works the same whether the client calls the generic /oauth/token endpoint or the per-server /oauth/mcp/:serverId/token endpoint — no client configuration is needed and nothing is stored server-side, the AI client holds the tokens. If a refresh token is invalid or expired, FlowCP returns invalid_grant and the client simply re-runs the normal authorization flow.

Custom domain (Bubble, Live)

If your Bubble app has a custom domain configured (detected automatically when you connect, or set under Settings), FlowCP sends users to Bubble OAuth on that domain for Live MCP servers — for example https://inova.us/api/1.1/oauth/authorize instead of *.bubbleapps.io. This avoids cross-domain login loops.

The FlowCP redirect URI (https://api.flowcp.io/oauth/callback) does not change. Register it with your provider as usual.

Updating credentials

To rotate a client secret:

  1. Generate a new secret with your provider.

  2. On the FlowCP OAuth page, click Edit on the config you want to rotate.

  3. Enter the new secret in the Client Secret field. Leave the Client ID unchanged. (Leaving the secret blank keeps the existing one.)

  4. Click Save changes.

New authorizations will use the new credentials. Users who have already authorized will continue working until their current access token expires, at which point the AI client will automatically trigger a new authorization using the updated credentials.

Deleting an OAuth config

Click the trash icon on a config to remove it. Any branches assigned to that config become unassigned and stop authenticating until you assign them another config. After deletion, no new authorizations can be completed with those credentials, and existing AI client sessions stop working once their current token expires.

After changing an app's provider

Changing an app's provider preserves your existing OAuth configs — they are attached to the app, not to the branches it re-creates, and the new branches re-inherit the app's default config. Review them afterwards, though: the appropriate OAuth provider differs between Bubble apps (which default to the Bubble provider) and generic OpenAPI or Git apps (which default to Generic OAuth2). Update or add a config so it matches the API you switched to.

UserInfo endpoint

FlowCP exposes a per-server userinfo endpoint so an AI client can resolve the connected account behind an access token:

The endpoint is advertised as userinfo_endpoint in each server's authorization-server discovery document (/.well-known/oauth-authorization-server/mcp/{serverId}), so OIDC-aware clients pick it up automatically. It is per-server because a bare access token doesn't say which OAuth config issued it — the serverId resolves the config and provider endpoints. The global discovery document does not advertise a userinfo endpoint.

FlowCP forwards the token to your provider's own userinfo endpoint and returns the normalized fields sub, email, and scope. It never stores the token.

Bubble apps: Bubble does not expose a userinfo endpoint by default, so this route returns userinfo_unsupported for Bubble configs unless you set a userInfoUrl in the config metadata. It works out of the box for Auth0, Clerk, Okta, Microsoft Entra ID, AWS Cognito, Keycloak, WorkOS (AuthKit), Zitadel, FusionAuth, Ory Hydra, Frontegg, Descope, Stytch, Supabase, and the Generic OAuth2 provider (with a discoverable or configured userInfoUrl).

Agent authentication discovery

Once a server uses user-context OAuth, FlowCP automatically advertises how AI agents can authenticate to it via the auth.md protocol — no extra setup required.

Last updated