# Auth.md: Authenticating an agent with Immersive Commons

Immersive Commons issues per-user agent tokens. An agent registers its
human once, receives a bearer token, then calls the MCP server, the A2A
endpoint, and the REST surface with it. Ten SIGNAL, presentations, news,
and donation tools are public and need no token.

## Discover

Machine-readable auth metadata (this file is the prose mirror):

- Authorization-server metadata (RFC 8414): https://www.immersivecommons.com/.well-known/oauth-authorization-server
  — carries the `agent_auth` extension block: `register_uri`, `claim_uri`,
  `verification_uri`, `revocation_uri`, `key_register_uri`, and
  `identity_types_supported`.
- Protected-resource metadata (RFC 9728): https://www.immersivecommons.com/.well-known/oauth-protected-resource
- Full manifest (scope catalog, endpoints, rate limits): https://www.immersivecommons.com/.well-known/ai-agent.json
- A2A agent card: https://www.immersivecommons.com/.well-known/agent-card.json

Note: API 401s do not yet carry a `WWW-Authenticate: Bearer
resource_metadata="..."` hint — start from this file or the well-known
documents above rather than probing for the header.

## Pick a method

`identity_types_supported` is `["anonymous"]`: the agent holds no prior
identity of its own; a signed-in human authorizes it. Identity chaining
via `identity_assertion` (e.g. `id-jag` /
`urn:ietf:params:oauth:token-type:id-jag`) is NOT offered. The credential
issued is an api_key-style bearer token.

Two registration paths:

1. **Device-code flow (RFC 8628, agent-driven — recommended).** No human
   credentials ever reach the agent. Steps in Register + Claim below.
2. **Browser mint (human-driven).** The human signs in at
   https://www.immersivecommons.com/floor10/agent-console, picks scopes, clicks Mint, and pastes
   the plaintext token into the agent's environment.

## Register

The `agent_auth.register_uri` is https://www.immersivecommons.com/api/agent/signup/start.

1. POST https://www.immersivecommons.com/api/agent/signup/start
   Body: `{ "scopes": ["read:public", "membership:read"], "client_name": "Your Agent" }`
   Returns: `{ device_code, user_code, verify_url, verify_url_complete, expires_in, interval }`.
   `scopes` is REQUIRED and non-empty; pick the narrowest set for your workflow.
2. Show the human `verify_url_complete` (or `verify_url` plus the `user_code`).
   They approve at https://www.immersivecommons.com/signup-with-agent while signed in.

## Claim

The `agent_auth.claim_uri` is https://www.immersivecommons.com/api/agent/signup/poll.

3. Poll GET https://www.immersivecommons.com/api/agent/signup/poll?device_code=<device_code> every `interval` seconds.
   Returns `{ "status": "pending" }` until approval, then ONCE
   `{ "status": "completed", agent_token, tier, granted_scopes, next_steps }`.
   Store `agent_token` immediately — it is delivered exactly once;
   subsequent polls return 410.

Deviations from stock RFC 8628 (tolerate these in a generic client):

- The token endpoint is polled with GET plus a `device_code` query param.
- The success field is `agent_token`, not `access_token`.
- Pending is `200 { "status": "pending" }`, not `400 authorization_pending`.

## Use the credential

Bearer `agt_<base64url-32bytes>`, sent as `Authorization: Bearer agt_...`.
The server stores only a SHA-256 of the token; the plaintext is shown
once at mint time and is individually revocable.

Connect it to any of the three equivalent surfaces:

- MCP (Streamable HTTP): https://www.immersivecommons.com/api/mcp. Add the URL to your client, paste `agt_...` in the Authorization header.
- A2A (JSON-RPC 2.0): https://www.immersivecommons.com/api/a2a
- REST: per-endpoint docs in https://www.immersivecommons.com/llms.txt and https://www.immersivecommons.com/.well-known/ai-agent.json

Scopes are tier-gated; the full catalog (id, description, tier) lives in
https://www.immersivecommons.com/.well-known/ai-agent.json (auth.schemes[0].scopes). Starter sets:

- Read only: `read:public`, `membership:read`
- Events and RSVP: add `events:read_upcoming`, `events:rsvp`
- Submit a highlight: add `events:submit_recap`, `directory:search`

Scopes cannot be added to an existing token — call the `ic_capabilities`
MCP tool to learn what a NEW token needs, then re-register.

### Optional: signed requests (RFC 9421)

Upgrade a bearer token to bearer plus Ed25519 signature so a leaked bearer
alone is useless. Bind a public key (Clerk session required, so a leaked
bearer cannot bind its own key):

- Register: POST https://www.immersivecommons.com/api/agent/keys/register
- Revoke: POST https://www.immersivecommons.com/api/agent/keys/revoke
- Enforce toggle: POST https://www.immersivecommons.com/api/agent/keys/enforce-toggle

Covered components, freshness window, and header examples are in
https://www.immersivecommons.com/.well-known/ai-agent.json (signed_requests block). Skill:
https://www.immersivecommons.com/skills/ic-signed-agent/SKILL.md.

## Errors

- `400 { "error": "missing_scopes" }` — registration POST without a
  non-empty `scopes` array; the response includes a usable example body.
- Over-scoped registration fails cleanly with structured `denied_scopes`
  (requested scopes above the human's tier).
- `401` / `403` — missing, malformed, unknown, or revoked bearer (no
  `WWW-Authenticate` challenge yet; see Discover).
- `410` — device code already consumed or expired; restart at Register.
- `429` — per-token daily write limits (see https://www.immersivecommons.com/pricing.md for the
  table); back off until the next UTC day.

If a documented surface doesn't match the deployed behavior, POST a
structured report to https://www.immersivecommons.com/api/agent/feedback
(kinds: broken_url, schema_mismatch, stale_doc, endpoint_404, other).
Out-of-band: admin@immersivecommons.com.

## Revocation

- **Self-revoke (agent-driven):** POST https://www.immersivecommons.com/api/agent/token/revoke with
  the bearer to revoke — a token can kill only ITSELF (no Clerk session
  needed; cross-token revoke is deliberately not possible from a token).
  Returns `200 { ok: true, revoked: true, prefix }`. Idempotent.
- **Console revoke (human-driven):** the advertised
  `agent_auth.revocation_uri` — https://www.immersivecommons.com/floor10/agent-console — where the
  signed-in human can revoke ANY of their tokens.
- **Key rotation:** POST https://www.immersivecommons.com/api/agent/keys/revoke clears an Ed25519
  binding (then re-register a fresh key).
