# auth.md

You are an agent. naymme (https://naymme.vercel.app) is a **public, unauthenticated service**: every endpoint works with no credential, and you can skip straight to Step 5. An OAuth 2.0 authorization server also exists — but only because some remote-MCP connectors (e.g. Poke) refuse servers that don't complete the handshake. If your client needs it, the full RFC 8414 discovery + RFC 7591 registration + authorization-code/PKCE flow is available and auto-approves; otherwise ignore it entirely.

## Step 1 — Discover

The structured discovery documents confirm the no-token tier:

- `GET https://naymme.vercel.app/.well-known/oauth-protected-resource` — RFC 9728 Protected Resource Metadata; declares the resource origin, the `public:read` scope and `authorization_servers: [https://naymme.vercel.app]` (resource-path variants like `/.well-known/oauth-protected-resource/api/mcp` also resolve)
- `GET https://naymme.vercel.app/.well-known/oauth-authorization-server` — RFC 8414 Authorization Server Metadata; advertises `authorization_endpoint`, `token_endpoint` and `registration_endpoint` for OAuth-requiring connectors
- `GET https://naymme.vercel.app/openapi.json` — OpenAPI 3.1 description of every endpoint
- `GET https://naymme.vercel.app/.well-known/mcp` — MCP discovery document (transport, tools, input schemas)
- `GET https://naymme.vercel.app/.well-known/mcp/server-card.json` — SEP-1649 MCP server card

## Step 2 — Pick a method

Two methods, both legitimate:

1. **Anonymous public access** (default) — call the endpoints directly; no API key, bearer token or account is ever required.
2. **OAuth 2.0 Authorization Code + PKCE** — only for connectors whose protocol mandates OAuth. The flow is fully machine-driven: dynamic registration, then an auto-approved authorize redirect — there is no login or consent page because the resource is already public.

## Step 3 — Register

Anonymous callers register nothing. OAuth clients register dynamically per RFC 7591:

```
curl -s -X POST https://naymme.vercel.app/oauth/register \
  -H 'content-type: application/json' \
  -d '{"client_name":"my-connector","redirect_uris":["https://you.example/callback"]}'
```

Returns `201` with `{ "client_id": "nmc.<signed registration>", ... }` — the client_id is a signed token carrying your registered redirect_uris, so nothing is stored server-side. redirect_uris must be https, http on loopback, or a private-use scheme. If you operate an agent, a descriptive `User-Agent` (e.g. `my-agent/1.0 (+https://you.example)`) is appreciated but not required or enforced.

## Step 4 — Claim ceremony

Anonymous access has no ceremony. OAuth clients run the standard exchange — the authorize endpoint auto-approves (no interstitial) since the resource is public:

1. `GET https://naymme.vercel.app/oauth/authorize?response_type=code&client_id=<id>&redirect_uri=<registered>&code_challenge=<S256>&code_challenge_method=S256&state=<state>` → 302 to your redirect_uri with `code` + `state`. PKCE S256 is mandatory; redirect_uri must match registration exactly.
2. `POST https://naymme.vercel.app/oauth/token` (form-encoded `grant_type=authorization_code&code=…&redirect_uri=…&client_id=…&code_verifier=…`) → `{ "access_token": "nmc.…", "token_type": "Bearer", "expires_in": 3600, "refresh_token": "nmc.…" }`. Codes expire in 5 minutes and are single-use.
3. Refresh with `grant_type=refresh_token`. Refresh tokens rotate and are single-use — always replace yours with the one in each response. Send the access token as `Authorization: Bearer …` — the API accepts it but does not require it.

The only scope is `public:read` — request it or omit `scope`; anything else returns `invalid_scope` (or `invalid_client_metadata` at registration).

## Step 5 — Use the public tier

Call any endpoint directly:

- `GET https://naymme.vercel.app/api/availability?name=<name>[&providers=<csv>]` — name availability results (v1 alias: `/api/v1/availability`)
- `GET https://naymme.vercel.app/api/score?name=<name>` — deterministic brand score (v1 alias: `/api/v1/score`)
- `POST https://naymme.vercel.app/api/mcp` — MCP Streamable HTTP transport, JSON-RPC 2.0 (v1 alias: `/api/v1/mcp`)
- `GET https://naymme.vercel.app/api/mcp` (also `/mcp`, `/health`) — endpoint status
- `GET https://naymme.vercel.app/api/markdown?path=</page>` — markdown representations of pages

A 401 never happens here — Bearer tokens are accepted but never required, and there is no credential that can lock you out.

## Rate limits

Limits are per client IP per 60-second window, enforced per server instance:

- `/api/availability` (+ `/api/v1/availability`, `/v1/check`) — 30 requests/minute (each request fans out to ~60 upstream checks)
- `/api/score` (+ `/api/v1/score`, `/v1/score`) — 60 requests/minute
- `/api/mcp` (+ `/api/v1/mcp`, `/v1/mcp`) — 60 requests/minute
- metadata/document endpoints (`/api/markdown`, `/api/openapi.json`, `/openapi.json`, `/v1`, API 404s) — 120 requests/minute

Every API response — including errors and 404s — carries RFC RateLimit headers: `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset` (seconds until the window resets) and `RateLimit-Policy` (e.g. `60;w=60` — the quota and window). Exceeding a limit returns `429` with `Retry-After` and an `{ "error": { "code": "rate_limited", ... } }` body. Set `NAYMME_RATE_LIMIT_RPM` when self-hosting to tune.

## Versioning

The API is version 1. `/api/v1/*` is canonical; the unversioned `/api/*` paths and the root-level `/v1/*` aliases (`/v1/check`, `/v1/score`, `/v1/mcp`, `/v1` version index) are the same handlers. Every response carries `API-Version: 1` and `X-API-Version: 1.0.0`. A future breaking v2 will keep v1 serving and mark it with `Deprecation: true` and `Sunset` headers plus a `Link: <…>; rel="deprecation"` pointer for at least 6 months before any removal.

## Headers

- `Accept: application/json` — JSON everywhere; unknown URLs (including unmapped `/api/*` paths) return a structured `{error:{code,message,hint}}` 404
- `Accept: text/markdown` — markdown representations of any page
- `Accept: application/json, text/event-stream` + `Content-Type: application/json` — required on `POST /api/mcp`
- `User-Agent` — a descriptive agent name is appreciated, e.g. `my-agent/1.0 (+https://you.example)`

## Errors

Every API error is structured: `{ "error": { "code": "<stable code>", "message": "<summary>", "hint": "<how to fix>", "details?": … } }`. Stable codes: `invalid_request`, `not_found`, `rate_limited`, `body_too_large`, `upstream_failed`, `too_many_sessions`, `internal_error`. MCP JSON-RPC errors keep their protocol shape and carry the hint under `error.data.hint`. Nothing here requires re-auth — there is no auth to renew.

## Revocation

Nothing needs revoking — OAuth tokens are self-contained and expire on their own (codes 5 minutes, access tokens 1 hour, refresh tokens 30 days). If a `429` arrives, honor `Retry-After`; if a `404` arrives on a previously working path, re-read `/openapi.json`.

## DNS-AID

This host documents its DNS-AID (draft-mozleywilliams-dnsop-dnsaid) SVCB/HTTPS records — the `_index._agents` organizational index pointer and the known-agent record — in DNS-AID.md in the repository.
