# Spekboom: authentication for agents

How an agent authenticates against Spekboom's MCP surface. Spekboom implements standard OAuth 2.1 with PKCE and dynamic client registration. It does not (yet) implement the auth.md agent-registration protocol (identity assertions, claim ceremonies): every grant is created by an interactive user sign-in and consent.

## What needs auth, what does not

- No auth: all discovery and planning tools on `https://mcp.spekboom.org/mcp` (`search_stays`, `plan_trip`, `check_availability`, `find_bird_species` and the rest). Just POST JSON-RPC.
- Guest auth (`guest:read`, `guest:write`): `list_my_bookings`, `create_booking_request`.
- Host auth (`host:read`, `host:write`): the host connector at `https://mcp.spekboom.org/host` (listings, calendar, pricing).

## Discovery

- Protected resource metadata (RFC 9728): `https://mcp.spekboom.org/.well-known/oauth-protected-resource`
- Authorization server metadata (RFC 8414): `https://www.spekboom.org/.well-known/oauth-authorization-server`
- An unauthenticated call to `https://mcp.spekboom.org/host` returns 401 with a `WWW-Authenticate: Bearer resource_metadata="..."` challenge pointing at the metadata above.

## Flow

1. **Register a client** (RFC 7591, no pre-approval needed): `POST https://www.spekboom.org/api/oauth/register` with `{ "client_name": "...", "redirect_uris": ["..."] }`. Public clients only; no client secret is issued.
2. **Authorize**: send the user to `https://www.spekboom.org/oauth/authorize` with `response_type=code`, your `client_id`, `redirect_uri`, PKCE `code_challenge` (S256), and `scope` (space-separated, from the four scopes below). The user signs in to Spekboom and approves the exact scopes requested. Requesting any scope outside the supported set is refused, not silently stripped.
3. **Exchange**: `POST https://www.spekboom.org/api/oauth/token` with `grant_type=authorization_code`, the `code`, your `code_verifier`, `redirect_uri` and `client_id`.
4. **Call**: send `Authorization: Bearer <access_token>` to the MCP endpoint. Access tokens live 1 hour; refresh with `grant_type=refresh_token` (refresh tokens live 90 days).

## Scopes

| Scope       | Grants                                                 |
| ----------- | ------------------------------------------------------ |
| guest:read  | Read the signed-in guest's own bookings                |
| guest:write | Create booking requests on the guest's behalf          |
| host:read   | Read the host's listings, calendar and bookings        |
| host:write  | Edit listings, block dates, manage the host's calendar |

Request only what you need: a read-only integration should ask for `guest:read` alone. Tokens whose grant lacks a needed scope get a structured JSON-RPC error telling them which scope to re-authorise with.

## Rules

- Never ask a user for their Spekboom password; the only sign-in is the hosted authorize page.
- Rate limits apply per token (120/minute); every response carries `RateLimit-*` headers.
- To revoke access, the user can email support@spekboom.org.

More: `https://www.spekboom.org/docs/mcp-connector` and `https://www.spekboom.org/openapi.json`.
