OAuth to Upstream MCPs (Gateway)¶
This document covers OAuth outbound from the platform to a remote MCP server it proxies. For OAuth inbound from clients (Claude Desktop) to the platform, see OAuth Server.
The two flows are separate, serve different purposes, and use independent storage:
| Concern | OAuth inbound (this platform as provider) | OAuth outbound (this platform as client) |
|---|---|---|
| Doc | oauth-server.md | this doc |
| Who is the OAuth provider? | this platform | the upstream MCP (Salesforce, vendor, etc.) |
| Who is the OAuth client? | Claude Desktop or another MCP client | this platform's gateway toolkit |
| Tokens stored at | oauth_clients (DCR) / session |
gateway_oauth_tokens (encrypted) |
| Use case | "let Claude Desktop call this platform" | "let this platform call a third-party MCP" |
Why outbound OAuth?¶
The gateway toolkit lets the platform proxy
upstream MCP servers and re-expose their tools as
<connection>__<remote_tool>. Many useful upstreams (Salesforce
Hosted MCP, vendor-specific MCPs, partner integrations) require
OAuth 2.1 to authenticate. The platform handles that flow for the
operator: one-time browser sign-in, then unattended token refresh —
including for cron jobs and scheduled prompts.
Supported grants¶
Two OAuth 2.1 grants are supported, configured per gateway connection in the admin portal:
client_credentials (machine-to-machine)¶
Use when the upstream issues a service token without human
interaction. Requires oauth_token_url, oauth_client_id,
oauth_client_secret, and (optionally) oauth_scope. The platform
fetches a token on first use and refreshes automatically as it
expires. No browser involved.
authorization_code + PKCE (browser sign-in)¶
Use when the upstream requires a human sign-in (Salesforce, most
vendor MCPs). The platform implements PKCE per RFC 7636 with the
S256 challenge method. Adds oauth_authorization_url to the
configuration.
After saving the connection, the operator clicks Connect in the admin portal:
1. Portal POST /api/v1/admin/gateway/connections/{name}/oauth-start
→ returns authorization URL with code_challenge, state, redirect_uri
2. Portal opens that URL in a new tab
3. Operator authenticates with the upstream
4. Upstream redirects browser to /api/v1/admin/oauth/callback?code=…&state=…
5. Platform exchanges the code for tokens at oauth_token_url
6. Tokens persisted to gateway_oauth_tokens (encrypted with ENCRYPTION_KEY)
7. Browser redirects back to /portal/admin/connections
Once connected, the access token is refreshed automatically using the stored refresh token. Cron jobs and scheduled prompts run untouched until the upstream invalidates the refresh token (operator clicks Reconnect to re-authorize).
Token storage¶
| Table | Holds | Encryption |
|---|---|---|
gateway_oauth_tokens |
access_token, refresh_token, expires_at, authenticated_by | AES-256-GCM via ENCRYPTION_KEY |
oauth_pkce_states |
code_verifier (paired secret), state, redirect_uri | AES-256-GCM via ENCRYPTION_KEY; rows expire after 10 min |
ENCRYPTION_KEY is required for any production gateway deployment
using OAuth. Without it, tokens and verifiers are stored in plaintext
and the platform logs a warning.
Multi-replica considerations¶
PKCE state must be visible across replicas: oauth-start may land on
replica A while the upstream's redirect lands the callback on replica
B. The platform automatically uses the Postgres-backed PKCE store when
a database is configured. Single-replica deployments can fall back to
the in-memory store.
Salesforce Hosted MCP setup walkthrough¶
Salesforce's Hosted MCP requires an OAuth client registration with the
Web Server Flow (the OAuth term Salesforce uses for
authorization_code). The high-level shape:
- Register an OAuth client in Salesforce that allows the Web
Server Flow. The exact path through Salesforce Setup depends on
your org's edition and Salesforce-Hosted-MCP rollout — refer to
Salesforce's current Hosted MCP / External Client App docs for the
step-by-step. What you need to capture from this step:
- Consumer key (becomes
oauth_client_id) - Consumer secret (becomes
oauth_client_secret) - Callback URL must be set to
https://<your-platform-host>/api/v1/admin/oauth/callback - Scopes that include OAuth basics (
api,refresh_token) plus the scope(s) Salesforce requires for Hosted MCP access — check the current Salesforce docs for the exact scope name(s).
- Consumer key (becomes
- Pick the right Salesforce OAuth endpoint base URL for your org:
- Production / Developer Edition orgs:
https://login.salesforce.com/services/oauth2/... - Sandbox orgs:
https://test.salesforce.com/services/oauth2/... - Orgs using My Domain:
https://<mydomain>.my.salesforce.com/services/oauth2/...
- Production / Developer Edition orgs:
- In the platform admin portal (
/portal/admin/connections), click + Add Connection and select kind mcp:- Endpoint: the Salesforce Hosted MCP URL
- Auth mode: OAuth 2.1
- Grant type: authorization_code + PKCE
- Authorization URL:
<base>/services/oauth2/authorize(from step 2) - Token URL:
<base>/services/oauth2/token - Client ID / Secret: the consumer key / secret from step 1
- Scope: the scopes you registered above (typically
api refresh_token+ the MCP-access scope)
- Save, click Connect, sign in to Salesforce, approve the scopes.
- The connection card shows "Authorized by
<email><time ago>", and Salesforce-MCP tools surface as<connection_name>__<remote_tool>intools/list. Personas with allow-globs matching that prefix can call them.
The platform refreshes the access token automatically using the stored refresh token. Scheduled prompts (cron jobs at 1 AM, etc.) run untouched until Salesforce invalidates the refresh token.
The Salesforce Setup UI navigation path and the exact MCP scope name change between editions and over time. Treat this walkthrough as the shape of the integration; verify the specifics against current Salesforce documentation before configuring a real org.
Related¶
- Gateway Toolkit — full connection-config reference
- Admin API: Gateway Endpoints —
oauth-start, callback, connection CRUD - Admin Portal: MCP Gateway Connections — UI walkthrough
- Operating Modes — DB / encryption requirements