On-Prem OAuth (Run-Hosted Connect)
By default the OAuth "connect" flow — where a user authorizes an integration and Willow stores the resulting tokens — runs on the Willow SaaS connect service. Run-hosted connect moves that flow onto your own run gateway instead, so the authorization-code exchange and token encryption happen entirely inside your infrastructure. The plaintext OAuth credentials never reach the Willow control plane.
You enable it per integration with a single toggle, and it only takes effect when that integration's run gateway is external (hybrid / on-prem).
When you need it
Use run-hosted connect when both are true:
- You run a hybrid or on-prem deployment, i.e. the integration's effective run gateway is an external gateway you host (see Gateway Settings).
- You must keep OAuth tokens and their encryption inside your boundary — for data-residency, network-isolation, or customer-managed-key (KMS) requirements — rather than having the SaaS connect service perform the code exchange.
If your run gateway is a Willow-hosted domain (mcp-s.com, withwillow.ai, or a custom domain still served by Willow), leave this off — the standard SaaS connect flow applies and there is nothing to gain here.
How it differs from the default
| SaaS connect (default) | Run-hosted connect | |
|---|---|---|
| Renders the consent/redirect pages | Willow SaaS connect | Your run gateway |
| Authorization-code → token exchange | Willow SaaS connect | Your run gateway |
| Token encryption | System KMS | Your gateway's key (static key or your AWS KMS) |
| Plaintext credentials reach the control plane | Yes (briefly, in memory) | No |
| Where tokens are stored | db-service (encrypted) | db-service (encrypted, already customer-owned ciphertext) |
Prerequisites
- A hybrid or on-prem deployment with an external run gateway configured for the organization. See Hybrid Deployment and Gateway Settings.
- The integration uses an OAuth-family auth type (OAuth, Instant/Willow OAuth, or Proxy OAuth). See Configure MCP Server Authentication.
- The run gateway can encrypt locally — either a static
ENCRYPTION_KEY, or AWS KMS (KMS=trueplusAWS_REGION/AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEYandKMS_KEY_ID). See Environment configuration. - The customer's OAuth application allows the run gateway's callback URL:
https://<your-run-host>/connect-auth/callback.
Enable it on an integration
The toggle lives on the MCP server's Settings tab and only appears when the integration's effective run gateway is external.
- Go to Build > MCP Servers and open the server.
- Select the Settings tab and expand Connect.
- Turn on Handle OAuth on the run gateway.
From then on, when a user connects that integration, Willow hands the OAuth flow to your run gateway's /connect-auth/init endpoint instead of the SaaS connect flow. See the Settings reference → Connect.
How it works
┌──────────────┐ 1. GET /auth/auth-url ┌───────────────────────────┐
│ SaaS connect │ ─────────────────────────────▶│ integration.connect_via_run│
│ (auth-url) │ │ + external run gateway? │
└──────┬───────┘ └────────────┬──────────────┘
│ yes: redirect browser to your gateway │ no: SaaS OAuth
▼ ▼
┌───────────────────────────────────────────────┐ (standard connect flow)
│ Your run gateway │
│ /connect-auth/init ── redirect ──▶ provider │
│ provider ── code ──▶ /connect-auth/callback │
│ exchange code → tokens (inside your network) │
│ encrypt tokens with your key (static / KMS) │
└───────────────┬────────────────────────────────┘
│ store already-encrypted credentials
▼
db-service (ciphertext only; never sees plaintext)
mcp-s-connect's auth-url route sees the integration has connect_via_run enabled and an external run gateway, so it redirects the browser to your gateway's/connect-auth/init(passing a signed state).- Your run gateway builds the provider authorize URL with
redirect_uri = https://<your-run-host>/connect-auth/callback. The redirect base is derived from the incoming request (X-Forwarded-Proto/X-Forwarded-Host, falling back toHost), so it matches the public URL the user is on. - The provider redirects back to your gateway's callback, which exchanges the code for tokens inside your network, encrypts them with your gateway's key, and stores the ciphertext through db-service. The SaaS control plane only ever sees encrypted data.
Environment configuration
Set these on the run gateway (see .env.example):
| Variable | Required | Purpose |
|---|---|---|
ENCRYPTION_KEY | One of key paths | Static key for local encryption (no AWS needed). |
KMS | For AWS KMS | Set true to use AWS KMS instead of a static key. |
KMS_KEY_ID | For AWS KMS | CMK id/ARN used to generate the data key. Required for this flow when using AWS KMS — unlike decryption, GenerateDataKey needs the key id. |
AWS_REGION / AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY | For AWS KMS | AWS credentials for the KMS calls. |
AUTH_SECRET | Yes | Verifies the signed connect state; must match the value mcp-s-connect signs with. |
DB_AUTH_SECRET | Optional | Fallback secret for verifying the signed state when it differs from AUTH_SECRET. |
Security notes
- Plaintext OAuth credentials never leave your infrastructure; db-service receives only ciphertext already encrypted with your gateway's key.
- The callback
redirect_urimust be registered on the provider's OAuth app, and your ingress must setX-Forwarded-Proto/X-Forwarded-Hostcorrectly (otherwise the gateway falls back to the rawHostheader, which must still be the public host). - Credentials encrypted this way are stamped for your external gateway, so decryption is always resolved locally and never routed to the system KMS.