Skip to main content
Version: Latest (1.9.x dev)

Authenticate MCP clients with OAuth 2.1

Use OAuth when each MCP client or user needs a distinct identity in your governance evidence. The DVARA MCP Gateway checks who issued the token, which Gateway it targets, which workspace it belongs to, and which MCP operations it allows before a tool request runs.

Enterprise only

Not included in DVARA Open Source.

OAuth is off by default. When it is off, MCP calls require a DVARA workspace API key. Turning it on accepts OAuth access tokens alongside API keys by default, which lets you migrate clients without interrupting them.

Configure an authorization server​

This example binds every accepted token from one issuer to the claims-production workspace:

dvara:
mcp-gateway:
oauth:
enabled: true
resource: https://gateway.internal.example.com/mcp
authorization-servers:
- issuer: https://login.internal.example.com
workspace: claims-production
scopes-supported:
- mcp:read
- mcp:call
enforce-scopes: true
api-keys-enabled: true
require-pkce: true

resource is the MCP Gateway's canonical URI and must appear in the token's aud claim. issuer must match the token's iss claim exactly. Both values must use HTTPS, except for a localhost development address.

When you do not set a key-set URI, DVARA first uses OAuth authorization-server discovery and then OpenID Connect discovery. With require-pkce: true, the default, discovered authorization metadata must advertise the S256 PKCE method. Restart the Gateway after changing these process settings.

SettingDefaultWhat it controls
enabledfalseWhether the MCP Gateway accepts OAuth access tokens and publishes protected-resource metadata.
enforce-scopestrueWhether each MCP operation requires its corresponding OAuth scope.
api-keys-enabledtrueWhether workspace API keys remain valid after OAuth is enabled.
require-pkcetrueWhether discovered authorization-server metadata must advertise PKCE with S256.
clients.allowedEmptyExact client IDs or HTTPS metadata-document prefixes that are allowed. An empty list does not restrict client IDs.
clients.require-metadata-documentfalseWhether a client must be allow-listed or use an HTTPS Client ID Metadata Document.
clients.dcr-sunsetNot setThe date after which clients treated as dynamically registered are refused.

Bind each token to a workspace​

Use the workspace setting on an issuer when that issuer serves one DVARA workspace. If the token also carries a workspace claim, it must match the configured workspace.

For an issuer shared by several workspaces, omit workspace and put the workspace ID in the token's dvara_workspace claim. Set workspace-claim when your issuer uses a different claim name. DVARA refuses a token when neither an issuer binding nor the configured claim identifies a workspace.

With scope enforcement enabled, clients need:

ScopeOperations
mcp:readInitialize an MCP session and list tools. It also covers reads on the server-scoped REST surface.
mcp:callCall a tool.

An OAuth token with no scopes is not unrestricted. That differs from a DVARA API key created without scopes.

Check what DVARA accepts​

DVARA accepts an asymmetric signed JWT only. The token must have a valid signature, sub, exp, matching iss, matching aud, and a usable workspace binding. It refuses unsigned and HMAC-signed tokens, expired or not-yet-valid tokens, and tokens sent in an access_token query parameter.

Fetch the protected-resource metadata without a credential:

curl --silent \
https://gateway.internal.example.com/.well-known/oauth-protected-resource/mcp
{
"resource": "https://gateway.internal.example.com/mcp",
"authorization_servers": ["https://login.internal.example.com"],
"scopes_supported": ["mcp:read", "mcp:call"],
"bearer_methods_supported": ["header"]
}

The metadata endpoint returns 404 while OAuth is disabled. When it is enabled, clients can use the document to find the authorization server and ask for the correct audience and scopes.

Now list tools with an access token:

curl --silent https://gateway.internal.example.com/mcp \
--header 'Authorization: Bearer <oauth-access-token>' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json, text/event-stream' \
--data '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}'

For a workspace with no visible tools, the JSON-RPC result is:

{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": []
}
}

Open Governance → Audit and inspect the resulting MCP event. OAuth calls record the authentication method, issuer, subject, and available client identity. DVARA never records the access token.

Control which clients can connect​

The token's client_id identifies the MCP client. DVARA also understands the common azp, cid, and appid claims when client_id is absent.

Set clients.allowed when you have a fixed client inventory. Each entry is an exact client ID or an HTTPS prefix ending in / for Client ID Metadata Documents. Once the list is nonempty, DVARA refuses every client that does not match it.

Without an allow-list, an HTTPS metadata-document client is accepted. Other client IDs are treated as dynamically registered. You can move away from that open posture in either of these ways:

  • Set clients.require-metadata-document: true to refuse non-metadata clients immediately.
  • Set clients.dcr-sunset to a planned cutoff date. DVARA accepts those clients before the date and refuses them after it.

Move from API keys without downtime​

Enable OAuth while leaving api-keys-enabled: true, which is the default. Move one MCP client at a time, then verify its workspace, subject, client ID, and scope in the audit trail. After every client uses OAuth, set api-keys-enabled: false and restart the Gateway.

This setting applies only to the MCP Gateway. It does not disable workspace API keys for the LLM or A2A Gateway.

Resolve authentication failures​

ResultMeaningWhat to check
400The credential was placed in the query string.Send Authorization: Bearer <token> instead.
401The token is missing, invalid, expired, or does not match the issuer, audience, or workspace.Follow the WWW-Authenticate link, then compare token claims with the resource metadata and issuer configuration.
403 with insufficient_scopeThe token is valid but lacks the operation's scope.Request mcp:read or mcp:call as appropriate.
Client refusedThe client fails the allow-list, metadata-document, or dynamic-registration cutoff rule.Check the resolved client ID and your client controls.

Never pass the caller's access token through to an upstream MCP server. If an upstream uses delegated authorization, send a separate upstream token as described in Govern tool calls with the MCP Gateway.