# Auth.md

## Mermail MCP authentication

Mermail supports two ways to authenticate to `POST /mcp`:

1. **OAuth 2.1 (recommended for interactive MCP clients)** — Authorization Code + PKCE. The user signs in with the same Firebase Google login as the Mermail console, picks a workspace, and the client receives a Bearer access token.
2. **Project API key (automation / CLI)** — `x-api-key: sk-proj-…` created in Settings → API Keys.

### OAuth discovery

- Origin resource metadata: `/.well-known/oauth-protected-resource`
- MCP resource metadata: `/.well-known/oauth-protected-resource/mcp`
- Authorization server metadata: `/.well-known/oauth-authorization-server`
- OpenID configuration: `/.well-known/openid-configuration`
- JWKS: `/.well-known/jwks.json`

Unauthenticated MCP calls return `401` with a `WWW-Authenticate` challenge pointing at the protected resource metadata.

### OAuth endpoints

| Endpoint | Purpose |
| --- | --- |
| `POST /oauth/register` | Dynamic client registration |
| `GET /oauth/authorize` | Browser consent (Mermail session + workspace picker) |
| `POST /oauth/token` | Authorization code / refresh token exchange |
| `POST /oauth/revoke` | Revoke a refresh token |

Scopes: `mcp:tools`, `openid`, `offline_access`.

### API key (non-OAuth)

```http
POST /mcp
x-api-key: sk-proj-…
```

### Agent client registration

Mermail supports anonymous OAuth client registration: registering the client
does not require or create a user identity. Agents register a public client with
`POST /oauth/register` and a JSON body containing `redirect_uris`,
`token_endpoint_auth_method: "none"`, and optional `client_name`.

After registration, create an S256 PKCE challenge and send the user to
`GET /oauth/authorize` with the returned `client_id`, an exact registered
`redirect_uri`, `response_type=code`, `scope=mcp:tools offline_access`, and
the PKCE parameters. This interactive authorization and workspace-consent
screen is the user claim step. Exchange the returned code at
`POST /oauth/token`. The resulting credential type is
`oauth2_access_token`, presented as a Bearer token to `POST /mcp`.

Revoke refresh tokens with `POST /oauth/revoke`. Never put access tokens,
refresh tokens, client secrets, or authorization codes in URLs or logs.

Mermail does not accept ID-JAG or anonymous user identity assertions and does not
expose an `/agent/identity` endpoint. Clients must not treat the OAuth client
ID as an agent identity assertion.
