Authio docs

Guides

Integrating MCP with Authio

Let MCP clients sign users in against your Authio-hosted authorization server, with CIMD as the primary identity model and DCR-with-IAT as the back-compat fallback.

The Model Context Protocol uses OAuth 2.1 to let AI clients access tool servers on a user’s behalf. The 2025-11-25 spec update adopted CIMD as the preferred client-identity mechanism, with DCR retained for backwards compatibility.

Step 1 — Flag your project as MCP

Go to Settings → Connect / MCP in the dashboard and check “MCP enabled.” This single click cascades:

  • cimd_enabledtrue
  • If dcr_mode = ‘disabled’: it bumps to ‘initial_access_token’ so MCP clients without CIMD have a working fallback.

Step 2 — Confirm the discovery document

Hit your project’s well-known URL:

curl https://auth-api.authio.com/.well-known/oauth-authorization-server \
  -H 'X-Authio-Project: proj_acme_prod' \
  | jq '. | {registration_endpoint, client_id_metadata_document_supported, mcp_authorization_supported}'

You should see:

{
  "registration_endpoint":                 "https://auth-api.authio.com/oauth2/register",
  "client_id_metadata_document_supported": true,
  "mcp_authorization_supported":           true
}

Step 3a (preferred) — Publish a CIMD document

Have the MCP server publish its metadata at a stable HTTPS URL. The MCP convention is https://<mcp-server>/.well-known/oauth-client-id.

{
  "redirect_uris":               ["https://my-mcp-server.example.com/oauth/callback"],
  "client_name":                 "My MCP Server",
  "client_uri":                  "https://my-mcp-server.example.com",
  "scope":                       "openid email mcp:read mcp:write",
  "grant_types":                 ["authorization_code", "refresh_token"],
  "response_types":              ["code"],
  "token_endpoint_auth_method":  "none",
  "software_id":                 "my-mcp-server",
  "software_version":            "1.4.0"
}

Test the resolution from the dashboard’s “Preview CIMD” button or via the API:

curl -X POST https://auth-api.authio.com/oauth2/cimd/resolve \
  -H 'X-Authio-Project: proj_acme_prod' \
  -H 'Content-Type: application/json' \
  -d '{"client_id":"https://my-mcp-server.example.com/.well-known/oauth-client-id"}'

Step 3b (fallback) — Register via DCR + IAT

For MCP clients that haven’t adopted CIMD yet:

  1. In the dashboard’s Connect / MCP tab, click “Issue IAT.” Hand the raw iatk_… token to the MCP client out of band.
  2. The MCP client registers:
curl -X POST https://auth-api.authio.com/oauth2/register \
  -H 'Authorization: Bearer iatk_DcGtZ5N…' \
  -H 'X-Authio-Project: proj_acme_prod' \
  -H 'Content-Type: application/json' \
  -d '{
    "redirect_uris":               ["https://my-mcp-server.example.com/oauth/callback"],
    "client_name":                 "My MCP Server",
    "token_endpoint_auth_method":  "none",
    "application_type":            "web"
  }'

Returns the standard RFC 7591 response. Because the IAT pinned token_endpoint_auth_method at none, there’s no client_secret — the MCP client uses PKCE on the authorization code exchange.

Step 4 — First sign-in

The MCP client hits /v1/auth/oauth/google/authorize (or your project’s configured authorize endpoint) with:

  • client_id: the CIMD URL (Step 3a) or the client_<24 hex> from Step 3b.
  • redirect_uri: must match one of the registered redirect URIs exactly.
  • response_type=code, code_challenge_method=S256, and a fresh code_challenge (PKCE is mandatory for public clients).

Authio resolves the CIMD URL (if applicable), validates the client, and runs the normal authorization-code flow. The resulting access token carries the project’s configured access-token TTL and includes RFC 8707 aud claims when the request supplied resource=<mcp-server-url>.

Operator follow-ups

Monitor oauth_client.cimd_fetch_failed audit events. A spike usually means an MCP server’s well-known endpoint is misconfigured (404, wrong content-type, or it’s serving from a CDN that strips the JSON body).
open mode + MCP is a viable combination only behind a Cloudflare WAF that rejects requests with suspicious user agents and request patterns. We recommend starting with initial_access_token mode and widening only when you’ve observed real-world traffic.

See also