# auth.md — Vendo Cloud agent registration

This file implements the [auth.md protocol](https://auth-md.com) (WorkOS,
built on RFC 9728 discovery and RFC 8628-style claim ceremonies). It teaches
AI agents how to register their user with Vendo Cloud and mint a
`VENDO_API_KEY` — no sign-up form, one human approval in the browser.

Agents: follow this file exactly. Ask your human before creating any account
or key.

## What you get

A **dev-mode Vendo Cloud API key** (`vnd_` + 40 lowercase hex) minted into
your user's organization — the same metered starter key `vendo init` issues.
Send it as `Authorization: Bearer vnd_...` to `https://console.vendo.run`,
or set it as `VENDO_API_KEY` in the host app's `.env.local`.

## Discovery

The protected resource is `https://console.vendo.run` (where you send the
Bearer token), so its RFC 9728 metadata is served authoritatively by the
console. vendo.run 302-redirects the discovery path there, so both work:

- Protected resource metadata (RFC 9728):
  `https://console.vendo.run/.well-known/oauth-protected-resource`
  (`https://vendo.run/.well-known/oauth-protected-resource` redirects here)
- Authorization server metadata (RFC 8414 + `agent_auth` block):
  `https://console.vendo.run/.well-known/oauth-authorization-server`

## Registration methods

### User-claimed (service_auth) — supported today

Device-authorization-style claim ceremony. Works with every agent.

**1. Open a claim** (anonymous; `login_hint` is optional but recommended —
it is shown to the human on the approval page):

```
POST https://console.vendo.run/api/v1/agent/claim
Content-Type: application/json

{ "login_hint": "dev@example.com" }
```

Response (`claim_token` and `device_code` are the same value; use whichever
your OAuth tooling expects):

```json
{
  "registration": "service_auth",
  "claim_token": "vct_…",
  "device_code": "vct_…",
  "user_code": "BCDF-GHJK",
  "verification_uri": "https://console.vendo.run/claim",
  "verification_uri_complete": "https://console.vendo.run/claim?code=BCDF-GHJK",
  "expires_in": 1800,
  "interval": 5
}
```

**2. Show your human the code.** Print `user_code` and
`verification_uri_complete` and ask them to approve the request in their
browser. They sign in to the Vendo console (or create an account with just an
email) and approve or deny. Codes expire after 30 minutes and are single-use.

**3. Poll the token endpoint** every `interval` seconds (form-encoded or
JSON; both grant types below are accepted):

```
POST https://console.vendo.run/api/v1/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=urn:workos:agent-auth:grant-type:claim&claim_token=vct_…
```

While pending you receive RFC 8628 §3.5 errors (HTTP 400, top-level
`error`): `authorization_pending` (keep polling), `slow_down` (add 5 seconds
to your interval), `expired_token` (open a fresh claim), `access_denied`
(the human said no — stop). On approval:

```json
{
  "access_token": "vnd_…",
  "token_type": "Bearer",
  "scope": "dev-mode",
  "meter": { "runs": { "included": 1000, "remaining": 1000 } }
}
```

`access_token` IS the `VENDO_API_KEY`. Write it to the host's `.env.local`;
never print it into logs or chat.

**Vendo CLI shortcut:** `vendo login` (alias: `vendo cloud device-login`)
runs this entire ceremony for you and writes `VENDO_API_KEY` to `.env.local`.
Agents should bound each call with `--wait <seconds>`: the command polls for
at most that long, then exits 0 with the ceremony still pending — re-running
`vendo login` resumes the same claim (same code, same approval page, until
the 30-minute expiry). `--wait 0` polls exactly once. Without `--wait` the
command blocks until the claim expires. The CLI deliberately sends no
`login_hint` — the human picks the account on the approval page — so there
is no email argument; the raw-HTTP claim above is where `login_hint` goes.
After the ceremony completes, re-run `vendo init` (it picks the key up from
`.env.local`) — or pass `--cloud-key <key>` explicitly.

### Registration endpoint (`identity_endpoint`)

`POST https://console.vendo.run/api/v1/agent/identity` with
`{ "type": "service_auth" }` (optionally plus `login_hint`) or
`{ "type": "anonymous" }` opens the same claim ceremony and returns it as a
WorkOS registration entry: `registration_type`, a top-level `claim_token`,
and a nested `claim` block (`user_code`, `verification_uri`,
`verification_uri_complete`, `expires_in`, `interval`). Any other `type`
answers `{ "error": "invalid_request" }`. Approve and poll exactly as above.

## Limits and revocation

- Claims: 30-minute expiry, single-use, at most 5 open claims per
  `login_hint`; the approval page allows 10 code attempts per user per
  10 minutes.
- Keys: at most 10 active dev-mode starter keys per organization; revoke and
  manage them on the console's Keys page (`https://console.vendo.run/keys`).
- Bring-your-own is always first-class: Vendo works with your own model key
  and infrastructure without any Vendo Cloud account (see
  `https://vendo.run/agents.md`).
