Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions docs/toolhive/concepts/auth-framework.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,14 @@ clients a spec-compliant OAuth experience while centralizing the complexity of
token acquisition and management.

To eliminate the client registration burden, the embedded authorization server
currently implements Dynamic Client Registration (DCR), which the MCP
specification lists as the backward compatibility fallback. Support for Client
ID Metadata Documents, the spec's preferred mechanism for clients and servers
without an existing relationship, is planned.
supports two client registration mechanisms. **Client ID Metadata Document
(CIMD)** is the MCP specification's preferred mechanism: a client presents a
public HTTPS URL as its `client_id`, and the embedded AS fetches and validates
the metadata document at that URL. Clients such as VS Code support CIMD and use
it automatically when the embedded AS advertises support. **Dynamic Client
Registration (DCR, RFC 7591)** is the backward-compatibility fallback. MCP
clients that do not support CIMD call `/oauth/register` to receive a `client_id`
automatically.

## Authentication framework

Expand Down
5 changes: 3 additions & 2 deletions docs/toolhive/concepts/backend-auth.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,9 @@ the external service, obtains tokens on behalf of the user, and automatically
forwards the upstream token to the MCP server on each subsequent request.

The embedded authorization server runs in-process within the ToolHive proxy with
no separate infrastructure needed. It supports Dynamic Client Registration
(DCR), so MCP clients can register automatically with ToolHive. No manual client
no separate infrastructure needed. It supports Client ID Metadata Documents
(CIMD) and Dynamic Client Registration (DCR), so MCP clients can identify
themselves or register automatically with ToolHive. No manual client
configuration in ToolHive is required.

For a full explanation of how the OAuth flow works, token storage and
Expand Down
82 changes: 76 additions & 6 deletions docs/toolhive/concepts/embedded-auth-server.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,14 @@ identity provider and those services.
From the client's perspective, the embedded authorization server provides a
standard OAuth 2.0 experience:

1. If the client is not yet registered, it registers via Dynamic Client
Registration (DCR, RFC 7591), receiving a `client_id` and `client_secret`. No
manual client registration in ToolHive is required.
1. The client identifies itself using one of two mechanisms, with no manual
registration in ToolHive required:
- **Client ID Metadata Document (CIMD):** If CIMD is enabled on the embedded
AS and the client supports it (for example, VS Code), the client presents
its public HTTPS metadata URL as its `client_id`. The embedded AS fetches
and validates the document.
- **Dynamic Client Registration (DCR, RFC 7591):** The client calls
`/oauth/register` to receive a `client_id` dynamically.
2. The client is directed to the ToolHive authorization endpoint.
3. ToolHive redirects the client to the upstream identity provider for
authentication (for example, signing in with GitHub or Atlassian).
Expand Down Expand Up @@ -132,9 +137,12 @@ the OAuth flow.

- **In-process execution:** The authorization server runs within the ToolHive
proxy with no separate infrastructure or sidecar containers.
- **Dynamic Client Registration (DCR):** Supports OAuth 2.0 DCR (RFC 7591),
allowing MCP clients to register automatically. No manual client registration
in ToolHive is required.
- **Client ID Metadata Document (CIMD):** When enabled, accepts HTTPS URLs as
`client_id` values and resolves client metadata on demand. Clients that
support CIMD (such as VS Code) use it automatically.
- **Dynamic Client Registration (DCR):** Supports OAuth 2.0 DCR (RFC 7591) as a
fallback for clients that do not support CIMD. MCP clients register
automatically with no manual configuration in ToolHive.
- **Direct upstream redirect:** Redirects clients directly to the upstream
provider for authentication (for example, GitHub or Atlassian).
- **Configurable signing keys:** JWTs are signed with keys you provide,
Expand Down Expand Up @@ -196,6 +204,68 @@ If you also set `baselineClientScopes`, those scopes apply to CIMD-resolved
clients too. Because CIMD clients can be resolved from arbitrary HTTPS URLs,
keep the baseline narrow.

### Two-layer architecture

The client's CIMD identity is used only within the embedded AS. The embedded AS
uses its own pre-configured upstream credentials when redirecting to the
upstream identity provider.

```mermaid
sequenceDiagram
participant Client as VS Code<br/>(CIMD client_id)
participant EmbeddedAS as Embedded AS
participant IDP as Upstream IDP

Note over Client,EmbeddedAS: Leg 1: CIMD
Client->>EmbeddedAS: client_id = https://vscode.dev/oauth/client-metadata.json
EmbeddedAS->>EmbeddedAS: Fetch and validate CIMD document
EmbeddedAS-->>Client: Redirect to upstream IDP

Note over EmbeddedAS,IDP: Leg 2: AS own credentials
Client->>IDP: Authenticate
IDP-->>EmbeddedAS: Authorization code
EmbeddedAS->>IDP: Exchange (AS's own client_id + secret)
EmbeddedAS-->>Client: Issue ToolHive JWT
```

The upstream IDP never sees the client's CIMD URL. This means you must still
configure an upstream client ID and secret for the embedded AS regardless of
whether clients use CIMD or DCR.

### Document validation

The embedded AS enforces the following rules on fetched CIMD documents:

- The URL must use `https` (loopback `http://localhost` is accepted in
development environments only).
- The `client_id` field inside the document must exactly match the URL it was
fetched from.
- `redirect_uris` must be present and pass strict validation.
- Symmetric shared-secret `token_endpoint_auth_method` values are forbidden.
- `grant_types` must include `authorization_code` and be a subset of
`[authorization_code, refresh_token]`.
- `response_types` must be a subset of `[code]`.
- Declared scopes must be a subset of the AS's configured `scopes_supported`
list (when set).

The fetcher also applies SSRF protection: DNS resolution runs before dialing,
private IP ranges are blocked, redirects are not followed, and each fetch is
subject to a five-second timeout and a 10 KB response cap.

### Verify CIMD is enabled

After applying the configuration, confirm that the discovery document advertises
CIMD support:

```bash
curl -s https://<YOUR_ISSUER_URL>/.well-known/oauth-authorization-server | \
python3 -m json.tool | grep client_id_metadata_document
```

Replace `<YOUR_ISSUER_URL>` with the `issuer` value from your
`MCPExternalAuthConfig`. You should see
`"client_id_metadata_document_supported": true`.

Comment on lines +255 to +268
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is procedural/how-to content in a concepts page, and it also duplicates the content from the actual guide. I would drop it from here.

Suggested change
### Verify CIMD is enabled
After applying the configuration, confirm that the discovery document advertises
CIMD support:
```bash
curl -s https://<YOUR_ISSUER_URL>/.well-known/oauth-authorization-server | \
python3 -m json.tool | grep client_id_metadata_document
```
Replace `<YOUR_ISSUER_URL>` with the `issuer` value from your
`MCPExternalAuthConfig`. You should see
`"client_id_metadata_document_supported": true`.

## Session storage

By default, session storage is in-memory. Upstream tokens are lost when pods
Expand Down
6 changes: 3 additions & 3 deletions docs/toolhive/concepts/vmcp.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,9 @@ vMCP can also run an embedded authorization server that handles the full OAuth
flow with multiple upstream identity providers (such as GitHub, Google, or
Okta). This enables per-user backend authentication: when a user logs in, the
auth server acquires tokens from each upstream provider and injects them into
requests to the appropriate backends. MCP clients register automatically through
Dynamic Client Registration (DCR), so no manual client configuration is needed.
See
requests to the appropriate backends. MCP clients register or identify
themselves automatically through Client ID Metadata Documents (CIMD) or Dynamic
Client Registration (DCR), so no manual client configuration is needed. See
[Authentication](../guides-vmcp/authentication.mdx#embedded-authorization-server)
for setup details.

Expand Down
33 changes: 33 additions & 0 deletions docs/toolhive/guides-k8s/auth-k8s.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1185,6 +1185,39 @@ kubectl describe mcpserver -n toolhive-system <name>
`kubectl logs -n toolhive-system -l app.kubernetes.io/name=toolhive-operator`
- Verify the operator is running: `kubectl get pods -n toolhive-system`

**CIMD client not using CIMD (falling back to DCR):**

- Verify `cimd.enabled: true` is set in the `MCPExternalAuthConfig` and the
operator has reconciled the change:
`kubectl describe mcpexternalauthconfig <name> -n toolhive-system`
- Confirm the discovery document advertises CIMD support:
```bash
curl -s https://<YOUR_ISSUER_URL>/.well-known/oauth-authorization-server | \
python3 -m json.tool | grep client_id_metadata_document
```
Replace `<YOUR_ISSUER_URL>` with the `issuer` value from your
`MCPExternalAuthConfig`. You should see
`"client_id_metadata_document_supported": true`.
- Restart the proxy runner pod after updating an existing resource.

**CIMD authentication failing with `invalid_client`:**

- The `client_id` field inside the fetched document must exactly match the URL
used to fetch it.
- Documents must not declare `token_endpoint_auth_method` values that use a
symmetric shared secret (`client_secret_post`, `client_secret_basic`,
`client_secret_jwt`).
- `grant_types` must include `authorization_code`. `response_types` must only
contain `code`.
- `redirect_uris` must be present and valid.

**CIMD fetch failing (egress / timeout):**

- The proxy runner pod needs outbound HTTPS access to the client's metadata URL
(for example, `https://vscode.dev`). Check cluster egress policies.
- Fetches time out after five seconds. Ensure the metadata host is reachable
from within the cluster.

</details>

<details>
Expand Down
36 changes: 22 additions & 14 deletions docs/toolhive/guides-ui/run-mcp-servers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,17 @@ remaining required information and adjust any optional settings as needed:
1. **Authorization method**: Choose how ToolHive should authenticate with the
remote server.\
The default is **Auto-Discovered**. Use this option for MCP servers that
fully implement the MCP authorization spec including dynamic client
registration (RFC7591) or for servers that do not require authentication.
ToolHive automatically:
- Discovers OAuth/OIDC endpoints
- Registers a new OAuth client
- Obtains and manages client credentials
- Handles token lifecycle automatically
implement the MCP authorization spec or for servers that do not require
authentication. ToolHive automatically discovers OAuth/OIDC endpoints and
identifies itself using whichever mechanism the server supports:
- **Client ID Metadata Document (CIMD):** If the server's discovery document
sets `client_id_metadata_document_supported: true`, ToolHive presents
[`https://toolhive.dev/oauth/client-metadata.json`](https://toolhive.dev/oauth/client-metadata.json)
as the `client_id`. No registration round-trip is needed.
- **Dynamic Client Registration (DCR, RFC 7591):** When CIMD is unavailable
or rejected, ToolHive registers an OAuth client dynamically.

Either path handles token acquisition and lifecycle automatically.

For MCP servers that accept a bearer token in the `Authorization` header,
select **Bearer Token**. ToolHive stores the token securely and sends it as
Expand Down Expand Up @@ -459,13 +463,17 @@ On the configuration form, enter:
6. **Authorization method**: Choose how ToolHive should authenticate with the
remote server.\
The default is **Auto-Discovered**. Use this option for MCP servers that
fully implement the MCP authorization spec including dynamic client
registration (RFC7591) or for servers that do not require authentication.
ToolHive automatically:
- Discovers OAuth/OIDC endpoints
- Registers a new OAuth client
- Obtains and manages client credentials
- Handles token lifecycle automatically
implement the MCP authorization spec or for servers that do not require
authentication. ToolHive automatically discovers OAuth/OIDC endpoints and
identifies itself using whichever mechanism the server supports:
- **Client ID Metadata Document (CIMD):** If the server's discovery document
sets `client_id_metadata_document_supported: true`, ToolHive presents
[`https://toolhive.dev/oauth/client-metadata.json`](https://toolhive.dev/oauth/client-metadata.json)
as the `client_id`. No registration round-trip is needed.
- **Dynamic Client Registration (DCR, RFC 7591):** When CIMD is unavailable
or rejected, ToolHive registers an OAuth client dynamically.

Either path handles token acquisition and lifecycle automatically.

For MCP servers that accept a bearer token in the `Authorization` header,
select **Bearer Token**. ToolHive stores the token securely and sends it as
Expand Down
7 changes: 5 additions & 2 deletions docs/toolhive/guides-vmcp/authentication.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -397,10 +397,13 @@ stored upstream tokens for backends.

Use the embedded authorization server when your backend MCP servers call
external APIs on behalf of individual users and no federation relationship
exists between your identity provider and those services. It also provides OAuth
exists between your identity provider and those services. It also supports OAuth
2.0 Dynamic Client Registration
([RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591)) and Client ID
Metadata Documents (CIMD) and Dynamic Client Registration
([RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591)), so MCP clients can
register automatically without manual client configuration in ToolHive.
identify themselves or register automatically without manual client
configuration in ToolHive.
Comment on lines +400 to +406
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this got garbled in an edit and now DCR is listed twice.

Suggested change
exists between your identity provider and those services. It also supports OAuth
2.0 Dynamic Client Registration
([RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591)) and Client ID
Metadata Documents (CIMD) and Dynamic Client Registration
([RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591)), so MCP clients can
register automatically without manual client configuration in ToolHive.
identify themselves or register automatically without manual client
configuration in ToolHive.
exists between your identity provider and those services. It also supports OAuth
2.0 Client ID Metadata Documents (CIMD) and Dynamic Client Registration
([RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591)), so MCP clients can
identify themselves or register automatically without manual client
configuration in ToolHive.


:::info

Expand Down