Getting started
Authentication
Every MCP and REST request uses an OAuth 2.1 bearer JWT, audience-bound to the surface it targets.
Discovery
Spec-compliant clients discover the Authorization Server (AS) via RFC 9728 + RFC 8414 metadata. Hit the protected-resource endpoint for the surface you want to call:
# MCP surface
GET https://mcp.mailnix.ch/.well-known/oauth-protected-resource
# REST surface
GET https://api.mailnix.ch/.well-known/oauth-protected-resourceFollow authorization_servers to the AS metadata document at https://app.mailnix.ch/.well-known/oauth-authorization-server: that document carries the issuer, JWKS, token endpoint, and supported grants.
Grant types
The AS supports three paths to a bearer:
- Anonymous bootstrap (
client_credentials): the seededmailnix-anonymous-bootstrapclient. One HTTP call, sandbox-only, no user identity required. This replaces the old dev_key handshake. - Authorization Code + PKCE S256: the standard interactive login. Pass
resource=https://mcp.mailnix.ch/mcporresource=https://api.mailnix.ch/v1to bind the issued token to the right audience. Limerion IDP handles the user-facing login. - Dashboard API keys: Settings → API keys lets you mint, rotate, and revoke keys in the web UI. The plaintext token is shown once on issuance.
Scopes & audience
Tokens are scoped and audience-bound per surface:
| Surface | Audience | Scopes |
|---|---|---|
| MCP | https://mcp.mailnix.ch/mcp | mcp:read / mcp:send-sandbox / mcp:send / mcp:admin |
| REST | https://api.mailnix.ch/v1 | api:read / api:send / api:admin |
A token minted for the REST audience cannot drive the MCP server (and vice versa). The browser-safe mnxpub_ publishable keys are pinned to /v1 only.
Refresh tokens
Refresh tokens rotate on every /oauth/token call. Presenting a rotated-out refresh token revokes the entire chain; that's the theft-detection signal. Store the most recent refresh token securely and discard older copies.
Auth errors
invalid_token: missing, expired, or wrong-audience bearer. The response carriesWWW-Authenticate: Bearer realm="mailnix"withresource_metadata=....insufficient_scope: token is authentic but missing the required scope tier (e.g.api:readpresented onPOST /v1/messages).forbidden: paused or banned project, or banned user.