# Shoplist Agent Authentication

Shoplist supports OAuth 2.0 with Dynamic Client Registration (RFC 7591)
and exposes the Model Context Protocol (MCP) at `/mcp`. Authorization
code with PKCE is the only supported user-facing flow.

## Discovery

- Authorization server metadata: `/.well-known/oauth-authorization-server`
- Protected resource metadata:    `/.well-known/oauth-protected-resource`
- MCP endpoint:                   `/mcp`

## Client registration (RFC 7591)

Agents register dynamically. No manual approval required.

    POST /api/oauth/register
    Content-Type: application/json

    {
      "client_name": "<human-readable name>",
      "redirect_uris": ["<https URI; http://localhost allowed for development>"],
      "token_endpoint_auth_method": "none" | "client_secret_post"
    }

Returns `client_id` (and `client_secret` for confidential clients).

## Authorization (code flow + PKCE)

    GET /oauth/authorize?
        response_type=code
        &client_id=<client_id>
        &redirect_uri=<registered URI>
        &scope=<space-separated scopes>
        &state=<opaque value>
        &code_challenge=<base64url SHA-256 of verifier>
        &code_challenge_method=S256

The user signs in via magic-link email, then approves:
1. The requested scopes.
2. One or more households the token may operate on.

## Token exchange

    POST /api/oauth/token
    Content-Type: application/x-www-form-urlencoded

    grant_type=authorization_code
    &code=<code from authorize redirect>
    &redirect_uri=<same as authorize>
    &client_id=<client_id>
    &code_verifier=<original PKCE verifier>

Returns:

    {
      "access_token": "<opaque>",
      "token_type": "Bearer",
      "expires_in": 3600,
      "refresh_token": "<opaque>",
      "scope": "<granted scopes>"
    }

Access tokens last 1 hour; refresh tokens last 30 days.

Refresh:

    POST /api/oauth/token
    Content-Type: application/x-www-form-urlencoded

    grant_type=refresh_token
    &refresh_token=<token>
    &client_id=<client_id>

## Scopes

| Scope             | Permits                                                       |
|-------------------|---------------------------------------------------------------|
| `list:read`       | Read the household's shopping list                            |
| `list:write`      | Add to / modify / purchase items on the list                  |
| `catalog:read`    | Read items, stores, and departments                           |
| `catalog:write`   | Add items, stores, and departments to the catalog             |
| `household:write` | Create new households and invite people to them               |

The authoritative list lives in `scopes_supported` on
`/.well-known/oauth-authorization-server`. Treat that as ground truth if
this document drifts.

## Household scoping

Tokens are bound to one or more *households* at consent time. MCP tools
that act on household-scoped data accept an optional `household_id`:

- Token authorizes **one** household → used implicitly.
- Token authorizes **multiple** → omitting `household_id` returns a
  structured `household_id_required` error with the available IDs.
- A `household_id` not in the token's authorized set → `household_not_authorized`.

The MCP tool `households_list` returns the IDs and names of authorized
households.

## Revocation

    POST /api/oauth/revoke
    Content-Type: application/x-www-form-urlencoded

    token=<access or refresh token>

Users may also revoke clients from the Integrations settings page.

## Rate limits

- `POST /api/oauth/token`:    20/min per (client, IP)
- `GET  /oauth/authorize`:    10/min per (user, IP)
- `POST /mcp`:                60/min per token

Exceeded → 429 with `Retry-After`.

## Audit

Successful token issuance, consent grant/deny, revocation, and every MCP
tool invocation are recorded. Token **values** are never logged; token
IDs are recorded for correlation.

## Endpoints (summary)

| Purpose                         | Method | Path                                      |
|---------------------------------|--------|-------------------------------------------|
| Auth-server discovery           | GET    | `/.well-known/oauth-authorization-server` |
| Protected-resource discovery    | GET    | `/.well-known/oauth-protected-resource`   |
| Dynamic client registration     | POST   | `/api/oauth/register`                     |
| User authorization              | GET    | `/oauth/authorize`                        |
| Token exchange / refresh        | POST   | `/api/oauth/token`                        |
| Token revocation                | POST   | `/api/oauth/revoke`                       |
| MCP JSON-RPC                    | POST   | `/mcp`                                    |
