# Cactus auth.md

You are an agent. What you need depends on what you are reading.

- A product's public help needs nothing: https://mcp.heycactus.ai/p/<product name>/mcp answers without an account, a key or a cookie, from that product's published pages first, and from its code when they fall short. Cactus's own is https://mcp.heycactus.ai/p/cactus/mcp.
- A team's own knowledge needs a member of the team. The team MCP address is https://mcp.heycactus.ai/mcp and the team A2A address is https://mcp.heycactus.ai/a2a. Sign in without a browser, sign in with one, or send a personal token.

The authorization server for those addresses is https://mcp.heycactus.ai. Its metadata, with the `agent_auth` block, is at https://mcp.heycactus.ai/.well-known/oauth-authorization-server. It grants two scopes:

- `cactus:read`: Read your team's pages, code map and past conversations
- `cactus:ask`: Ask Cactus questions and start investigations; each creates a conversation

## Sign in without a browser

For a CLI, a server job or any agent that cannot open a browser for its person. This is auth.md's registration (https://github.com/workos/auth.md): `anonymous`, and `service_auth` when you know your person's email already. `identity_assertion` is refused with `issuer_not_enabled`: Cactus trusts no other provider's word for a person.

### 1. Register

```http
POST https://mcp.heycactus.ai/agent/identity
Content-Type: application/json

{ "type": "anonymous", "name": "<what to call you on the claim page>" }
```

Or `{ "type": "service_auth", "login_hint": "<your person's email>", "name": "..." }`. `name` is optional and is shown to your person as your own words. An address may register ten times an hour.

The answer carries `claim_token` and `claim_url`, and for `anonymous` an `identity_assertion`. Keep `claim_token` in memory until the claim is done.

### 2. A token for public help

```http
POST https://mcp.heycactus.ai/token
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=<identity_assertion>
```

This token reads what anybody reads with no sign-in: a product's published help. It carries no scope, and every team tool refuses it.

### 3. Your person claims you

```http
POST https://mcp.heycactus.ai/agent/identity/claim
Content-Type: application/json

{ "claim_token": "<claim_token>", "email": "<your person's email>" }
```

The answer's `claim_attempt` holds `user_code`, `verification_uri`, `expires_in` and `interval`. A `service_auth` registration had them in its `claim` block already. Show your person the link and the six-digit code in one message: the link opens the claim page on app.heycactus.ai, where they sign in, see the name you gave and the address you registered through, and type the code. Only the person with that email can claim you. A code lasts ten minutes and takes five wrong tries; ask `claim_url` again for a new one.

Poll every `interval` seconds:

```http
POST https://mcp.heycactus.ai/token
Content-Type: application/x-www-form-urlencoded

grant_type=urn:workos:agent-auth:grant-type:claim&claim_token=<claim_token>
```

`authorization_pending` means they have not typed it yet, and `expired_token` that the code ran out. Then the answer is a token with the scopes a browser sign-in gives (`cactus:read cactus:ask`) and a new `identity_assertion`. The claim ends the public token, and the first assertion stops working.

### 4. Use it, renew it, revoke it

Send `Authorization: Bearer <access_token>`. The token is for https://mcp.heycactus.ai, so it works on https://mcp.heycactus.ai/mcp, https://mcp.heycactus.ai/a2a and every product's address there. heycactus.ai signs agents in the same way under its own name, at https://heycactus.ai/oauth/agent/identity and https://heycactus.ai/oauth/token, for https://heycactus.ai/a2a. A token lasts an hour. For the next one, exchange your latest `identity_assertion` as in step 2; that revokes the token before it, so one agent holds one token. A claimed agent stays signed in for thirty days, then registers again. To revoke a token, POST `token=<access_token>` to https://mcp.heycactus.ai/token.

## Sign in with a browser

An OAuth client registers at https://mcp.heycactus.ai/register (RFC 7591) or names itself with a client ID metadata document, then signs its person in at https://mcp.heycactus.ai/authorize with PKCE (S256) and exchanges the code at https://mcp.heycactus.ai/token. The person approves it on app.heycactus.ai.

## A personal token

A person on the team mints one on the AI clients page in the Cactus app, and it goes in the install command as `Authorization: Bearer <token>`. With it, nothing asks for a sign-in.
