# MailSentry authentication

Two ways in:

- **API key** (`ms_...`) — for the REST API and for MCP. Simple, long-lived, full account access.
- **OAuth 2.1** — for MCP clients only (Claude, ChatGPT connectors). Scoped, revocable, no
  key-pasting. Metadata: [/.well-known/oauth-authorization-server](https://mailsentry.pro/.well-known/oauth-authorization-server).

There is still no OIDC provider and no `/.well-known/openid-configuration`: this issues
opaque access tokens, not identity claims.

## Getting a key

1. Create an account at <https://mailsentry.pro/signup>. This is a web form; there is no
   signup API. It asks for a full name, an email address and a password (minimum 6
   characters).
2. Confirm the emailed link. The account is inactive until you do.
3. Open <https://mailsentry.pro/dashboard/settings> and create a key. It is shown once.

Confirming the emailed link starts a 7-day free trial with Starter-level quota (100,000
verifications per day). No credit card is required to sign up.

## Using a key

Send it as an HTTP Bearer token on every request:

```
Authorization: Bearer ms_YOUR_API_KEY
```

Keys always start with `ms_`. The same key authenticates both the REST API and the MCP
server at <https://mailsentry.pro/mcp>.

```bash
curl https://mailsentry.pro/api/v1/verify \
  -H "Authorization: Bearer ms_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"email":"name@example.com"}'
```

## Failures

| HTTP | `code` | Meaning |
| --- | --- | --- |
| 401 | `auth_header_missing` | No `Authorization: Bearer ...` header was sent. |
| 401 | `invalid_api_key` | The key is unknown, revoked or deactivated. |
| 403 | `quota_exceeded` | Authentication succeeded; the daily quota is spent. A free, untrialled key has a quota of 0, so it authenticates and then returns this on every verify. |
| 429 | `rate_limit_exceeded_api` | Per-key rate limit for your plan. |
| 429 | `rate_limit_exceeded_ip` | Per-IP ceiling on `/api/v1`. |
| 429 | `rate_limit_exceeded_mcp` | Per-IP limit on `/mcp` (120/min, not plan-scoped). |

Branch on `code`, never on the human-readable `error` string.

## Scope

An **API key** carries the full access of the account behind it; scopes are not
selectable when issuing one.

An **OAuth token** carries only what the human ticked on the consent screen:

| Scope | Allows |
| --- | --- |
| `email:verify` | Spend credits verifying addresses (`verify_email`, `verify_batch`) |
| `usage:read` | Read today's count, quota and plan (`get_usage`) |
| `account:read` | Read account id, email, plan, status (`get_account`) |

A client that requests no scope gets the two read-only ones — never the spending scope.
OAuth tokens are accepted at `/mcp` only, and are bound to that resource; they do not work
on `/api/v1`. Connected apps can be revoked from the dashboard.

## OAuth flow

Authorization code with PKCE (S256 required — `plain` is rejected). Dynamic client
registration is open at `POST /oauth/register`, so an MCP client can connect with no
prior arrangement. Access tokens last 30 minutes; refresh tokens rotate on every use and
reusing a rotated one revokes the whole family.

## Keeping it safe

Keep the key server-side. It is a bearer credential: anyone holding it can spend your
daily quota. Revoke and reissue from the same Settings page if it leaks.

Full reference: <https://mailsentry.pro/llms.txt>
