Authenticate an MCP server with OAuth
Do this when a remote MCP server rejects a static token and expects an OAuth authorization-code flow. Use Pass secrets to an MCP server instead when the provider issues a long-lived API key you can paste. AgentArea acts as the OAuth client. It discovers the authorization server from the MCP endpoint, registers itself, runs PKCE, and stores the resulting token as an auth config linked to the instance. The agent never sees the token.Prerequisites
- A
url-type MCP instance that already exists. OAuth connect resolves the remote URL from the instance’s parent spec and returns 400 if there is none — create the instance first with Connect a remote MCP server. - The provider’s MCP endpoint must publish protected-resource metadata (RFC 9728) so the authorization server can be discovered.
- Redis reachable from the API. The in-flight flow state lives there between the two requests.
- A browser. The authorization step requires a human at a consent screen.
Steps
1. Start the flow
authorize_url in a browser
yourself.
Behind that single call AgentArea discovers the authorization server from the MCP
URL, registers as a client via Dynamic Client Registration where the provider
supports it, generates a PKCE S256 pair, and stores the flow state in Redis keyed
by state.
return_to is where the browser lands afterwards. It is validated against an
allowed base, so an arbitrary URL is rejected.
2. Complete consent in the browser
Open the URL, approve the scopes. The provider redirects toGET /v1/mcp-oauth/callback with code and state.
The callback is public — it must be, because the provider redirects a browser to
it — and it is protected by the state token rather than your API key. It
exchanges the code for tokens, writes an auth config of type oauth2 holding the
access token, refresh token, scope, and expiry, links it to the instance via
auth_config_id, and then redirects the browser to
{return_to}/mcp-servers/{instance_id}?oauth=success.
Tool discovery is kicked off in the background at that point, so the tool list
may be a moment behind the redirect.
3. Handle a provider without dynamic registration
Some authorization servers do not implement RFC 7591. The flow then needs a pre-registered OAuth app, supplied to the API as environment variables:/authorize returns 502 naming the issuer that refused
registration.
Verify
Confirm the instance now carries an auth config and that a call through the governed proxy succeeds with an injected token.Authorization header is stripped before the request goes upstream, so this
only succeeds if the OAuth credential was stored correctly.
Troubleshooting
400 “Instance has no remote URL configured”. The instance isdocker or
command, not url. OAuth connect only applies to remote servers; a managed
workload takes its credential from the environment instead.
502 “OAuth discovery failed”. The MCP endpoint does not publish
protected-resource metadata, or the authorization server metadata document is
unreachable. Confirm the provider documents OAuth for MCP; if it uses a plain API
key, use Pass secrets to an MCP
server.
502 naming the issuer and Dynamic Client Registration. The authorization
server has no registration endpoint, or registration failed. Register an OAuth
app manually and set MCP_OAUTH_CLIENT_ID and MCP_OAUTH_CLIENT_SECRET.
The callback reports an invalid or expired state. Flow state is held in Redis
with a bounded lifetime and is consumed on first use. A stale browser tab, a
second attempt at the same authorize_url, or a Redis restart between the two
steps all produce this. Start again from /authorize.
return_to is ignored or rejected. It is validated against an allowed
frontend base to stop the callback becoming an open redirect. Use your
deployment’s configured frontend origin.
Calls start failing with 401 days later. The stored refresh token is used to
mint new access tokens, and some providers rotate refresh tokens on each use. If
a refresh fails the connection needs re-authorizing — re-run /authorize for the
same instance.
Two auth configs for one instance. Each successful flow creates a new auth
config named mcp-oauth-{first 8 chars of instance id} and repoints
auth_config_id. Older configs are left behind; the instance uses only the one
it points at.