---
title: "cf0 authentication for agents"
description: "How an agent gets a credential for the cf0 MCP server."
canonical: "https://cf0.ai/auth.md"
---

# cf0 authentication for agents

This guide tells an agent how to get a credential for cf0. It follows the sections of the auth.md format (https://workos.com/auth-md).

The public REST API (https://cf0.ai/api/public/listings) needs no credential. Only the MCP server (https://api.cf0.ai/mcp) needs a credential. The MCP server acts for one person who has a cf0 account.

## Discover

1. Send a request to https://api.cf0.ai/mcp with no token. The server sends HTTP 401 with this header:

   `WWW-Authenticate: Bearer resource_metadata="https://api.cf0.ai/.well-known/oauth-protected-resource/mcp", scope="openid email profile user:org:read offline_access"`

2. Read the protected resource metadata (RFC 9728) at https://api.cf0.ai/.well-known/oauth-protected-resource. It gives `resource` and `authorization_servers`.
3. Read the authorization server metadata (RFC 8414) at https://clerk.cf0.ai/.well-known/oauth-authorization-server.

The authorization server metadata has no `agent_auth` block. cf0 does not publish an `identity_endpoint` or a `claim_endpoint`.

## Pick a method

cf0 supports one method: delegated user access with OAuth 2.1.

| Identity type | Supported | Note |
| --- | --- | --- |
| User-delegated OAuth 2.1 | Yes | Authorization code with PKCE (S256), from ChatGPT, Claude or Claude Code only |
| `anonymous` | No | Use the public REST API without a credential |
| `identity_assertion` (ID-JAG, `urn:ietf:params:oauth:token-type:id-jag`) | No | |
| `service_auth` | No | |

## Register

The client registers with a Client ID Metadata Document (CIMD). The authorization server metadata has `client_id_metadata_document_supported: true`. The `client_id` is the HTTPS URL of the client metadata document. cf0 has no dynamic client registration endpoint.

The MCP server accepts tokens from these clients only:

- ChatGPT: `https://chatgpt.com/oauth/<id>/client.json`
- Claude: `https://claude.ai/oauth/mcp-oauth-client-metadata`
- Claude Code: `https://claude.ai/oauth/claude-code-client-metadata`

A token from a different client gets HTTP 403 with `{"error":"unsupported_client"}`. To use cf0 from a different agent, send the person to https://cf0.ai/list, or use the public REST API.

## Claim

A person must sign in to cf0 and give consent. Open the authorization endpoint https://clerk.cf0.ai/oauth/authorize with these parameters:

- `response_type=code`
- `client_id` (your CIMD URL)
- `redirect_uri`
- `code_challenge` and `code_challenge_method=S256`
- `scope=openid email profile user:org:read offline_access`
- `resource=https://api.cf0.ai/mcp`

## Exchange

Send the code and the `code_verifier` to the token endpoint https://clerk.cf0.ai/oauth/token. You get an `access_token` and, with `offline_access`, a `refresh_token`.

## Use the access_token

Send the token in the header of each MCP request:

`Authorization: Bearer <access_token>`

The token acts for the person who gave consent, and only in the cf0 organization of that person.

## Errors

| Status | Body | What to do |
| --- | --- | --- |
| 401 | `{"error":"unauthorized"}` (no token) or `{"error":"invalid_token"}`, and a `WWW-Authenticate` header | Get a token, or refresh the token |
| 403 | `{"error":"insufficient_scope"}` and a `WWW-Authenticate` header | Ask for the scopes in the `WWW-Authenticate` header again |
| 403 | `{"error":"unsupported_client"}` | The client is not ChatGPT, Claude or Claude Code. See Register |
| 429 | `{"error":"rate_limited"}` and `Retry-After` (`events/subscribe` only) | Wait for the number of seconds in `Retry-After` |

A tool call that is over the rate limit, or that the person cannot do, gets an MCP tool result that tells why. It does not get an HTTP error.

## Revocation

Revoke a token at https://clerk.cf0.ai/oauth/token/revoke (RFC 7009). A person can also remove the app in the settings of ChatGPT or Claude.

## Contact

luca@cf0.ai
