# Cactus help auth.md

You are an agent. A public site needs no sign-in: every page on it is read without an account, a key or a cookie, starting at https://cactus.heycactus.ai/llms.txt. The MCP address https://mcp.heycactus.ai/p/cactus/mcp is anonymous too, and answers from the published pages only.

A site its team keeps to itself reads to a member of the team: in a browser signed in to Cactus, or to an agent sending `Authorization: Bearer <token>` with a token from this site's own sign-in. This site is an authorization server over the one Cactus sign-in; its metadata, with the `agent_auth` block, is at https://cactus.heycactus.ai/.well-known/oauth-authorization-server.

## 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://cactus.heycactus.ai/oauth/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://cactus.heycactus.ai/oauth/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://cactus.heycactus.ai/oauth/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://cactus.heycactus.ai/oauth/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://cactus.heycactus.ai, where it reads this site's text if your person's team keeps it; to use it on the MCP address instead, add `resource=https://mcp.heycactus.ai/p/cactus/mcp` when you mint it. 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://cactus.heycactus.ai/oauth/token.

## Sign in with a browser

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

## What stays closed

- A draft, or a page meant for one person, is not reachable from this site or its MCP address, signed in or not.
- A page kept for the team, and the team's own conversations, read only to a member of the team.
- The team's sources and settings are never reachable here.
- `contact_team` sends the team a message with an address they can reply to, and that is all an anonymous caller can do for the team.
