auth.md
MachineMail Overview
MachineMail gives every AI agent its own email address, ensuring that the inbox is secure and cannot be hijacked. The service supports agentic registration with these steps:
- Discover
- Register
- (Claim if needed)
- Exchange for an access_token
- Call the API
- Handle revocation
Resource Information
- Resource API:
https://machinemail.dev/v0(REST) - Authorization server:
https://machinemail.dev - Registration types:
anonymous,service_auth - Pricing
- Terms
- Acceptable use
- Privacy
- Support: support@machinemail.dev
- Full API reference: Documentation
Step 1 — Discover
A 401 Unauthorized response from the API and MCP servers indicates a need for metadata:
API Unauthorized:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://machinemail.dev/.well-known/oauth-protected-resource"
MCP Unauthorized:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://mcp.machinemail.dev/.well-known/oauth-protected-resource/mcp"
Protected Resource Metadata
GET https://machinemail.dev/.well-known/oauth-protected-resource
{
"resource": "https://machinemail.dev/",
"resource_name": "MachineMail",
"resource_logo_uri": "https://machinemail.dev/favicon.svg",
"authorization_servers": [ "https://machinemail.dev" ],
"scopes_supported": [ "inboxes.read", "inboxes.write", "messages.read", "messages.send", "messages.write", "webhooks.read","webhooks.write", "domains.read", "domains.write", "lists.read", "lists.write", "metrics.read", "pods.read", "pods.write", "api_keys.read", "api_keys.write" ],
"bearer_methods_supported": [ "header" ],
"resource_documentation": "https://machinemail.dev/auth.md"
}
Authorization Server Metadata
GET https://machinemail.dev/.well-known/oauth-authorization-server
{
"resource": "https://machinemail.dev/",
"authorization_servers": [ "https://machinemail.dev" ],
"scopes_supported": [ "inboxes.read", "inboxes.write", "messages.read", "messages.send", "messages.write", "webhooks.read","webhooks.write", "domains.read", "domains.write", "lists.read", "lists.write", "metrics.read", "pods.read", "pods.write", "api_keys.read", "api_keys.write" ],
"bearer_methods_supported": [ "header" ],
"issuer": "https://machinemail.dev",
"authorization_endpoint": "https://machinemail.dev/oauth2/authorize",
"token_endpoint": "https://machinemail.dev/oauth2/token",
"registration_endpoint": "https://machinemail.dev/oauth2/register",
"revocation_endpoint": "https://machinemail.dev/oauth2/revoke",
"device_authorization_endpoint": "https://machinemail.dev/auth/cli/device/code",
"jwks_uri": "https://machinemail.dev/.well-known/jwks.json",
"service_documentation": "https://machinemail.dev/docs/agents/mcp",
"grant_types_supported": [ "authorization_code", "refresh_token", "urn:ietf:params:oauth:grant-type:device_code", "urn:ietf:params:oauth:grant-type:jwt-bearer", "urn:workos:agent-auth:grant-type:claim" ],
"response_types_supported": [ "code" ],
"response_modes_supported": [ "query" ],
"code_challenge_methods_supported": [ "S256" ],
"token_endpoint_auth_methods_supported": [ "none", "client_secret_post", "client_secret_basic" ],
"revocation_endpoint_auth_methods_supported": [ "none", "client_secret_post", "client_secret_basic" ],
"client_id_metadata_document_supported": true,
"authorization_response_iss_parameter_supported": true,
"agent_auth": {
"skill": "https://machinemail.dev/auth.md",
"identity_endpoint": "https://machinemail.dev/agent/identity",
"claim_endpoint": "https://machinemail.dev/agent/identity/claim",
"events_endpoint": "https://machinemail.dev/agent/event/notify",
"identity_types_supported": ["anonymous", "service_auth"],
"identity_assertion": { "assertion_types_supported": [] },
"events_supported": []
}
}
Step 2 — Pick a Method
Choose one of the following:
- Mint an ID-JAG for the audience (
aud=https://machinemail.dev) from a trusted provider. (identity_assertion not available yet). - Use user email for service_auth. A claim ceremony is required; nothing works until the user confirms.
- Select anonymous for immediate access (sandbox inbox on
machinemail.dev) which will expire unless claimed later.
Step 3 — Register
Anonymous Registration
POST https://machinemail.dev/agent/identity
Content-Type: application/json
{ "type": "anonymous", "name": "optional label" }
{
"registration_id": "reg_...",
"agent_id": "reg_...",
"registration_type": "anonymous",
"identity_assertion": "<service-signed JWT>",
"assertion_expires": "2026-05-04T13:00:00.000Z",
"pre_claim_scopes": [ "inboxes.read", "messages.read", "messages.send", "messages.write" ],
"claim_url": "https://machinemail.dev/agent/identity/claim",
"claim_token": "clm_...",
"claim_token_expires": "2026-05-04T13:00:00.000Z",
"post_claim_scopes": [ "inboxes.read", "inboxes.write", "messages.read", "messages.send", "messages.write", "webhooks.read", "webhooks.write", "domains.read", "domains.write", "lists.read", "lists.write", "metrics.read", "pods.read", "pods.write", "api_keys.read", "api_keys.write" ],
"inbox": {
"inbox_id": "agent-xxxx@machinemail.dev",
"email": "agent-xxxx@machinemail.dev",
"ephemeral": true,
"expires_at": "..."
}
}
Service Authentication
POST https://machinemail.dev/agent/identity
Content-Type: application/json
{ "type": "service_auth", "login_hint": "user@example.com" }
{
"registration_id": "reg_...",
"agent_id": "reg_...",
"registration_type": "service_auth",
"claim_url": "https://machinemail.dev/agent/identity/claim",
"claim_token": "clm_...",
"claim_token_expires": "...",
"post_claim_scopes": [ "inboxes.read", "inboxes.write", "messages.read", "messages.send", "messages.write", "webhooks.read", "webhooks.write", "domains.read", "domains.write", "lists.read", "lists.write", "metrics.read", "pods.read", "pods.write", "api_keys.read", "api_keys.write" ],
"claim": {
"user_code": "123456",
"expires_in": 600,
"verification_uri": "https://machinemail.dev/claim?claim_attempt_token=cat_...",
"interval": 5
}
}
Step 4 — Claim Ceremony
To claim an anonymous registration:
POST https://machinemail.dev/agent/identity/claim
Content-Type: application/json
{ "claim_token": "clm_...", "email": "user@example.com" }
Completing the Claim
The email parameter is optional but recommended. Use the user's real email for claiming the agent.
Poll for Completion
For successful claim completion, make a token request:
POST https://machinemail.dev/oauth2/token
Content-Type: application/x-www-form-urlencoded
grant_type=urn:workos:agent-auth:grant-type:claim&claim_token=clm_...
{
"access_token": "<post-claim access_token>",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "inboxes.read inboxes.write messages.read messages.send messages.write webhooks.read webhooks.write domains.read domains.write lists.read lists.write metrics.read pods.read pods.write api_keys.read api_keys.write",
"identity_assertion": "<service-signed JWT>",
"assertion_expires": "..."
}
Step 5 — Use Access Token
GET https://machinemail.dev/v0/inboxes
Authorization: Bearer <access_token>
Scopes
| Scope | Grants | Pre-claim |
|---|---|---|
inboxes.read |
List and read inboxes. | yes (sandbox only) |
inboxes.write |
Create, update, and delete inboxes. | no |
messages.read |
Read messages, threads, attachments, and trust reports. | yes (sandbox only) |
messages.send |
Send, reply to, and forward messages. | yes (sandbox only) |
messages.write |
Change labels on and delete messages. | yes (sandbox only) |
webhooks.read |
List webhooks and deliveries. | no |
webhooks.write |
Create, update, and delete webhooks. | no |
domains.read |
List domains and their DNS records. | no |
domains.write |
Manage custom domains. | no |
lists.read |
Read allow/block lists. | no |
lists.write |
Manage allow/block lists. | no |
metrics.read |
Read metrics and event logs. | no |
pods.read |
List pods. | no |
pods.write |
Manage pods. | no |
api_keys.read |
List API keys. | no |
api_keys.write |
Manage API keys. | no |
Errors
| Code | Where | Action |
|---|---|---|
anonymous_not_enabled |
/agent/identity |
Pick another method. |
invalid_request |
/agent/identity, /agent/identity/claim, /oauth2/token |
Fix the request body. |
interaction_required (401) |
/agent/identity |
Surface the claim block to the user. |
claimed_or_in_flight (409) |
/agent/identity/claim |
Poll for token. |
registration_blocked (403) |
/agent/identity |
Registration not available from network. |
Revocation
- Credential revocation:
POST https://machinemail.dev/oauth2/revokewithtoken=<access_token>&token_type_hint=access_token. - Registration revocation: humans can also revoke from the dashboard.