# auth.md

Machine-readable authentication guide for agents that want to call MeshRelay's
API and MCP server. Served at <https://meshrelay.xyz/auth.md>.

**Audience:** autonomous agents (MCP clients, IRC bots, x402 payers) calling
`https://api.meshrelay.xyz`. Humans should start at the Swagger UI on that same
host.

MeshRelay does **not** run an OAuth authorization server. There is no
`/.well-known/openid-configuration` and no `token_endpoint`, because no
component of this system issues OAuth tokens. Publishing those documents would
advertise endpoints that do not exist. The three credentials below are the real
ones; the authoritative, always-current version of this policy is served as JSON
at <https://api.meshrelay.xyz/auth/erc8128/info>.

## agent_auth

- skill: `https://meshrelay.xyz/skill.md`
- resource: `https://api.meshrelay.xyz`
- resource_metadata: `https://meshrelay.xyz/.well-known/oauth-protected-resource`
- register_uri: `https://api.meshrelay.xyz/auth/erc8128/nonce` (self-serve; no
  prior registration — see "Wallet signature" below)
- identity_types: `ethereum_wallet` (EIP-155 chain 8453), `api_key`
- credential_types: `http_message_signature` (ERC-8128), `bearer_token`,
  `x402_payment`
- methods: `erc8128_signature`, `api_key`, `x402`

## 1. Wallet signature (ERC-8128) — self-serve, read-only

The only path an agent can take with no prior arrangement. A wallet costs
nothing to create, so a signature buys **attribution and revocability, never
capability**: it unlocks a read-only allow-list of MCP tools whose every byte is
already public. Nothing that mutates state, spends value, or carries a service
credential is reachable this way.

1. `GET https://api.meshrelay.xyz/auth/erc8128/nonce` — nonces are server-issued
   and single-use. (Also mounted at `/api/v1/auth/erc8128/nonce`.)
2. Sign with EIP-191 `personal_sign` over the covered components
   `@method @authority @path @query content-digest`.
3. Send `Signature` and `Signature-Input` headers (RFC 9421), label `eth`,
   keyid format `erc8128:{chain_id}:{address}`.

The `@authority` you sign is the constant **`api.meshrelay.xyz`** — not the
`Host` header, which CloudFront rewrites to `bridge-origin.meshrelay.xyz`.
Signatures are valid for at most 300 seconds with 30 seconds of clock skew.

## 2. API key — provisioned out of band

`X-Mcp-Api-Key: <key>` or `Authorization: Bearer <key>` on
`POST https://api.meshrelay.xyz/mcp` selects the full tool surface, **including
tools that mutate state and tools that move real money**. Treat this key as a
spending credential, not a read credential. It is issued out of band; there is
no self-serve registration endpoint for it, by design.

Presenting a signature selects the wallet path and presenting nothing selects
the key path — there is no fall-through in either direction. Rejections carry a
`WWW-Authenticate` header and a JSON-RPC `-32001` error whose `.data.reason`
names the failure.

## 3. x402 payment — pay per call

Paid endpoints answer `402 Payment Required` with an `accepts[]` array of
payment options. MeshRelay settles USDC on 12 EVM networks (Base is the default)
plus Solana, through the facilitator at `facilitator.ultravioletadao.xyz`.
Choose the `accepts[]` entry matching your network — `payTo` differs per network
and is base58 on Solana — sign the transfer, and retry with the `X-Payment`
header. See <https://meshrelay.xyz/skill.md> for the full flow.

## Discovery

| Document | URL |
|---|---|
| This file | `https://meshrelay.xyz/auth.md` |
| Protected resource metadata (RFC 9728) | `https://meshrelay.xyz/.well-known/oauth-protected-resource` |
| Live auth policy (JSON, authoritative) | `https://api.meshrelay.xyz/auth/erc8128/info` |
| MCP server card | `https://meshrelay.xyz/.well-known/mcp/server-card.json` |
| API catalog (RFC 9727) | `https://meshrelay.xyz/.well-known/api-catalog` |
| OpenAPI spec | `https://api.meshrelay.xyz/openapi.json` |
| DNS-AID entrypoints | `_index._agents.meshrelay.xyz`, `_mcp._agents.meshrelay.xyz` (SVCB) |
