Connector authentication
Connector authentication supplies credentials to upstream MCP servers and HTTP APIs. It is separate from signing in to the Aperture gateway and from configuring credentials for model providers. This topic explains the authentication model and the auth configuration object.
Shared credentials and per-user authorization
Aperture supports two credential models:
- Shared credentials: Bearer tokens, API keys, HTTP Basic authentication, and OAuth 2.0 client credentials authenticate requests with the same credential for every permitted user. Scope these credentials narrowly, preferably read-only.
- Per-user authorization: OAuth 2.0 authorization code and dynamic client registration require each user to consent. Aperture stores each user's tokens separately and uses isolated MCP client sessions.
Upstream credentials do not replace Aperture connector grants. A user needs both a matching grant and any required upstream authorization. The configured Tailnet connector has a separate, tool-initiated authorization flow for each node it provisions.
Authentication types
The auth object's type field selects the authentication scheme. The following table describes the available auth types:
| Type | Required fields | Description |
|---|---|---|
bearer_token | secret | Static Authorization: Bearer <secret> header. |
api_key | secret, name, in | Credential injected as a named header or query parameter. in must be "header" or "query". |
basic | username, password | HTTP Basic authentication. |
oauth2_client_credentials | client_id, client_secret, token_url | Machine-to-machine OAuth 2.0 token. Auto-refreshed. Optional scopes array. |
oauth2_authorization_code | client_id, auth_url, token_url | Per-user OAuth 2.0 consent flow. Optional client_secret (not required for PKCE-only), scopes, auth_params, and redirect_uri. |
oauth2_dcr | None | Per-user OAuth 2.0 consent flow using dynamic client registration. Aperture discovers the authorization server and registers a client at runtime, so no client_id, auth_url, or token_url is needed. Optional url (defaults to the connector's server-level url), scopes, auth_params, and redirect_uri. |
The auth block rejects unknown fields. A typo in a field name (for example, "secert" instead of "secret") produces a validation error at load time.
Scheme-specific behavior
Bearer token
This example supplies a shared bearer token to an MCP server:
{
"connectors": {
"servers": {
"snowflake": {
"protocol": "mcp",
"url": "https://mcp.example.com/v1/mcp",
"auth": {
"type": "bearer_token",
"secret": "sk-example-token"
}
}
}
}
}
API key
This example sends an API key in the X-API-Key header:
{
"connectors": {
"servers": {
"weather": {
"protocol": "http",
"url": "https://api.weather.example.com",
"auth": {
"type": "api_key",
"secret": "wk-example-key",
"name": "X-API-Key",
"in": "header"
}
}
}
}
}
The in field must be "header" or "query". When set to "header", Aperture injects the credential as a request header with the name specified in name. When set to "query", Aperture appends it as a URL query parameter.
OAuth 2.0 client credentials
This example obtains a shared OAuth token with client credentials:
{
"connectors": {
"servers": {
"analytics": {
"protocol": "mcp",
"url": "https://analytics.example.com/v1/mcp",
"auth": {
"type": "oauth2_client_credentials",
"client_id": "aperture-analytics",
"client_secret": "secret-example",
"token_url": "https://auth.example.com/oauth2/token",
"scopes": ["read:data"]
}
}
}
}
}
Per-user OAuth 2.0 authorization code flow
When a connector uses oauth2_authorization_code, each user must complete an individual consent flow. Aperture uses PKCE with the S256 challenge method. Each user gets an isolated MCP client session, so backends that tie session state to a bearer token cannot mix up cross-user state.
auth_params
The auth_params field appends custom parameters to both the authorization URL and the token exchange request body. Some providers require specific parameters to issue refresh tokens:
- Google:
{"access_type": "offline", "prompt": "consent"}. Withoutaccess_type: offline, Google does not issue a refresh token.
If you use your own OAuth client for a Google Workspace connector, create it in a Google Cloud project enrolled in Google's Workspace Developer Preview Program. Credentials from a project that is not enrolled fail to authorize. With Aperture's pre-registered client, you can use QuickSetup without creating a project or OAuth client.
This example uses your own Google OAuth client with offline access:
{
"connectors": {
"servers": {
"google": {
"protocol": "mcp",
"url": "https://mcp.google.example.com/v1/mcp",
"auth": {
"type": "oauth2_authorization_code",
"client_id": "example-client-id",
"client_secret": "example-client-secret",
"auth_url": "https://accounts.google.com/o/oauth2/v2/auth",
"token_url": "https://oauth2.googleapis.com/token",
"scopes": ["https://www.googleapis.com/auth/spreadsheets.readonly"],
"auth_params": {"access_type": "offline", "prompt": "consent"}
}
}
}
}
}
Dynamic client registration (oauth2_dcr)
oauth2_dcr is a per-user OAuth 2.0 flow for MCP servers that support dynamic client registration (RFC 7591). Instead of registering an OAuth application yourself and supplying a client_id, auth_url, and token_url, Aperture discovers the authorization server from the connector's url (RFC 9728 protected-resource metadata, then RFC 8414 authorization-server metadata) and registers a client at runtime.
The url field is the MCP server's resource URL. If you omit it, Aperture uses the connector's server-level url. Optional scopes, auth_params, and redirect_uri are supported. You do not supply a client ID or secret. Aperture obtains client credentials through registration.
A DCR connector uses the same per-user connect flow, token lifecycle, and capability population as oauth2_authorization_code. By default, oauth2_dcr connectors on a gateway share the callback https://<aperture-hostname>/aperture/auth/dcr/callback. A configured auth.redirect_uri overrides that default. Some verified DCR providers, such as Vercel, accept only Aperture's public callback. For those providers, a custom auth.redirect_uri is not supported. DCR requires upstream support for protected-resource discovery, authorization-server metadata, and dynamic client registration.
This example configures a DCR connector:
{
"connectors": {
"servers": {
"atlassian": {
"protocol": "mcp",
"url": "https://mcp.atlassian.com/v1/mcp/authv2",
"auth": {
"type": "oauth2_dcr",
"url": "https://mcp.atlassian.com/v1/mcp/authv2"
}
}
}
}
}
Per-user connection lifecycle
Initiating the flow
Connect and disconnect apply only to connectors that use a per-user interactive OAuth flow (oauth2_authorization_code or oauth2_dcr). The built-in Tailnet connector is an exception. It authorizes through its tools, not through Connect.
To start authorization in Chat:
- Open Connectors.
- Find the connector under Connect to use.
- Select Connect.
After provider consent, the provider redirects to the callback selected for the connector. Aperture returns the browser to the connector detail page and shows Connected.
Pending authorization flows expire after 15 minutes. If a flow expires, select Connect again.
OAuth callback selection
The callback depends on how the OAuth client is configured:
- Your own OAuth client: Register
https://<aperture-hostname>/aperture/auth/<connector-id>/callbackwith the provider. The connector ID must match the key underconnectors.servers. If you setauth.redirect_uri, register that URI instead. - Supported QuickSetup clients: When you keep a verified provider's pre-registered Aperture client ID, Aperture uses its managed public callback on gateways with managed callback routing. No manual callback registration is needed. A custom
auth.redirect_uriis rejected for these managed clients. Use your own OAuth client if you need a custom redirect URI. - Dynamic client registration: Aperture registers the callback with the provider automatically. The default is
https://<aperture-hostname>/aperture/auth/dcr/callback, shared by DCR connectors on the gateway, rather than a per-connector path. If configured,auth.redirect_urioverrides it. Some verified DCR providers, such as Vercel, accept only Aperture's public callback. For those providers, a customauth.redirect_uriis not supported.
Use the callback URL that Aperture shows for your connector.
Token lifecycle
Aperture stores tokens per user and treats them as expired 60 seconds before their actual expiry, triggering a refresh on the next request. If a token becomes unusable, the connector shows Needs reconnect. The user selects Reconnect in Chat Connectors to authorize again. Selecting Disconnect on the connector detail page removes the current user's stored token, so that user must select Connect again before using the connector.
Capability population
Connectors using oauth2_authorization_code or oauth2_dcr populate their tool catalog for each user after authorization, rather than at startup. The built-in Tailnet connector is an exception, because it authorizes through its tools. Aperture fetches capabilities with that user's credentials and caches them per connector and user. Authenticated discovery and tool requests populate the cache if it is empty. Tools from a per-user connector do not appear in tools/list for a user until that user has authorized them.
After authorization, the connector detail page in Chat shows available capabilities. Select Refresh tools to contact upstream with your credentials and request current tools.
Set up a connector
Follow the guide for your connector and credential model:
- Set up an authenticated MCP connector for shared credentials.
- Set up a per-user OAuth 2.0 connector for individual consent.
- Set up an HTTP API connector for an authenticated API proxy.
- Add a verified connector for provider defaults and QuickSetup.