# auth.md

How an AI agent authenticates to MiniMailer, the EU-resident email API with a native MCP server.
This document is for agents and the developers who run them. Machine-readable metadata:

- Authorization server: https://minimailer.app/.well-known/oauth-authorization-server
- Protected resource (`/mcp/v1`): https://minimailer.app/.well-known/oauth-protected-resource/mcp/v1
- MCP server card: https://minimailer.app/.well-known/mcp/server-card.json

## Accounts

MiniMailer is in a private beta. Accounts are created by invitation only, and an agent cannot create one on its own.
A person joins the waitlist at https://minimailer.app and receives an invitation when the beta opens to them; the OAuth and token methods below then work for that account.

## Method 1 — OAuth 2.1 for MCP clients

Use this when the agent runs inside an MCP client that can open a browser for the account owner to approve access.

1. Read the authorization-server metadata at https://minimailer.app/.well-known/oauth-authorization-server.
2. Register a client with a `POST` to https://minimailer.app/oauth/register, sending `client_name` and `redirect_uris`. Registration needs no credentials and returns a public client: `client_id`, no secret, `token_endpoint_auth_method: none`. A redirect URI outside the allowed set answers `invalid_redirect_uri`.
3. Run the authorization-code flow with PKCE (`S256`) at https://minimailer.app/oauth/authorize, requesting the `mcp:use` scope plus any REST scope the agent needs. The account owner approves the request in the browser.
4. Exchange the code at https://minimailer.app/oauth/token. The response carries an access token and a refresh token; `refresh_token` is the only other grant the token endpoint accepts.
5. Present the access token as `Authorization: Bearer <token>` to the MCP endpoint at https://minimailer.app/mcp/v1 (Streamable HTTP).
6. Revoke a token you no longer need with a `POST` to https://minimailer.app/oauth/revoke (RFC 7009).

## Method 2 — claim ceremony (`service_auth`) for agents without a browser

Use this when the agent cannot open a browser itself but can show the account owner a short code. It binds the agent to an existing account; no account is created. The metadata for it is the `agent_auth` block of the authorization-server document (`identity_types_supported: ["service_auth"]`).

1. Register a client at https://minimailer.app/oauth/register as in method 1; clients registered there carry the device authorization grant this ceremony needs. A client created in the dashboard works only if it was created with that grant — one without it is refused at the next step with `unauthorized_client`, so register a new client instead.
2. `POST` to the identity endpoint https://minimailer.app/oauth/agent/identity with `type=service_auth`, `client_id`, and optionally `scope` (defaults to `mcp:use`). `login_hint` is accepted and ignored: it is never stored, echoed or looked up, so the answer never reveals whether an account exists.
3. The response carries `claim_token`, `user_code`, `verification_uri`, `verification_uri_complete`, `expires_in` (10 minutes) and `interval` (seconds between polls).
4. Show the owner the `user_code` and `verification_uri` (https://minimailer.app/oauth/device). They sign in, enter the code, see exactly which scopes the token will carry, and approve or deny.
5. Poll `POST https://minimailer.app/oauth/token` with `grant_type=claim`, `claim_token`, and `client_id`, no faster than `interval`. While the owner has not decided you get `authorization_pending`; too-fast polling gets `slow_down`; a denial gets `access_denied`; after 10 minutes `expired_token`. Once approved you get the same access + refresh token pair as method 1.
6. To tell this server a token should no longer be used, either revoke it at https://minimailer.app/oauth/revoke or post a `urn:minimailer:agent-auth:token-revoked` event with the token to the events endpoint https://minimailer.app/oauth/agent/events.

Under the auth.md names this is the OAuth 2.0 device authorization grant (RFC 8628): `claim_token` is the device code, and `grant_type=urn:ietf:params:oauth:grant-type:device_code` with `device_code` is accepted as the same thing.

Two auth.md dialects exist and the `agent_auth` block carries both, describing this one ceremony: the specification's field names (`identity_endpoint`, `claim_endpoint`, `events_endpoint`, `identity_types_supported: ["service_auth"]`) and the older names readiness scanners check (`identity_assertion.assertion_types_supported: ["verified_email"]`, `credential_types_supported`, `claim_uri`, `revocation_uri`). `verified_email` is the reference implementation's own name for `service_auth`; no identity-assertion (ID-JAG) token is accepted.

## Method 3 — personal access token

Use this for CI and REST calls where a person can hand the agent a credential. The account owner creates the token in the dashboard under **API Tokens**, choosing its scopes and an expiry of 1, 6 or 12 months. The value is shown once.

- Send it as `Authorization: Bearer <token>` on every request. Never put it in a URL.
- REST API: the JSON:API surface described at https://api.minimailer.app/openapi.yaml (media type `application/vnd.api+json`).
- MCP: the same token works at https://minimailer.app/mcp/v1 when it carries the `mcp:use` scope.

## Scopes

- `emails:send` — Send transactional emails
- `emails:read` — Read sent email history and statistics
- `emails:write` — Update and delete email records
- `campaigns:write` — Create, update, and dispatch campaigns
- `campaigns:read` — Read campaign history and statistics
- `contacts:write` — Create, update, and delete contacts and audiences
- `contacts:read` — Read contacts and audiences
- `inbound:read` — Read inbound email records
- `domains:write` — Register and manage sending domains and inboxes
- `domains:read` — Read domain and inbox configuration
- `webhooks:write` — Create, update, and delete webhooks
- `webhooks:read` — Read webhook configuration
- `suppressions:write` — Remove email addresses from the suppression list
- `suppressions:read` — Read the suppression list
- `compliance:write` — Execute GDPR right-to-forget and data-subject requests
- `tokens:write` — Create and revoke API tokens
- `mcp:use` — MCP server access for AI agents

## What is not offered

- No agent self-registration of accounts: every account is created and owned by a person, and every token is approved by that person.
- No identity-assertion (ID-JAG) and no anonymous agent registration. `identity_types_supported` lists `service_auth` only.
- No `client_credentials` grant.

## Further reading

- Getting started: https://minimailer.app/docs/getting-started
- MCP server, tools and examples: https://minimailer.app/docs/mcp
- Agent skill: https://minimailer.app/.well-known/agent-skills/minimailer/SKILL.md
