# auth.md — Agent authentication for What's On Durham

> How automated agents should access https://whatsondurham.com and https://api.whatsondurham.com.

## Audience

Automated agents, crawlers, and tools that read Durham events, places, news, and itineraries from What's On Durham. Humans use the website UI; agents should follow this file instead of inventing API keys.

## Summary

- **Public read needs no login.** HTML, sitemaps, `llms.txt`, ARD catalog, Agent Skills, and Worker GET APIs are open.
- **OAuth discovery documents exist for Agent Readiness**, but **authorization and token endpoints refuse issuance** (HTTP 501). Do not expect bearer tokens for public agents.
- **Agent registration:** **anonymous only** — there is no account signup via agents. `register_uri` and `claim_uri` point back to this file.
- **Remote MCP** is available at `https://api.whatsondurham.com/mcp` (see `/.well-known/mcp/server-card.json`). Tools are unauthenticated read-only (`search_site`, `get_api_health`).
- **Browser WebMCP** tools also run in the visitor's tab (origin script + optional Cloudflare edge bridge).

## Registration / provisioning

| Flow | Support |
|------|---------|
| Anonymous | **Yes** — no credential; use open GET / MCP tools |
| Verified email / ID-JAG | **No** |
| OAuth client registration | **No** — `/oauth/authorize` and `/oauth/token` return 501 |

Do not `POST /agent/auth`. Operator bearer secrets exist only for internal routes and are never issued to third-party agents.

## OAuth / OIDC discovery (read-only metadata)

- Authorization Server: https://whatsondurham.com/.well-known/oauth-authorization-server
- OpenID configuration: https://whatsondurham.com/.well-known/openid-configuration
- Protected Resource: https://whatsondurham.com/.well-known/oauth-protected-resource
- JWKS (empty): https://whatsondurham.com/.well-known/jwks.json

`agent_auth` on the Authorization Server document:

- `identity_types_supported`: `["anonymous"]`
- `register_uri` / `claim_uri`: this file (`https://whatsondurham.com/auth.md`)
- `anonymous.credential_types_supported`: `["none"]`

## Supported methods

| Method | Use |
|--------|-----|
| Unauthenticated HTTPS GET | Public HTML, Markdown negotiation, discovery docs, Worker GET APIs |
| Remote MCP (`/mcp`) | `tools/list` + `tools/call` for search/health (no auth) |
| Browser WebMCP (visitor tab) | Optional in-page tools when `modelContext` is available |
| Turnstile + allowlisted origin | Required for public POSTs (submit forms, chatbot ask) with a human in the loop |
| Operator bearer secret | Internal only — not available to public agents |

## Credential use

Public reads and public MCP tools need no credential. Do not send forged Bearer tokens, API keys, or Turnstile tokens. If a response is 401/403 on an operator route, stop — that route is out of scope for agents.

## Read access (preferred)

1. Prefer Markdown negotiation: `Accept: text/markdown` on HTML page URLs.
2. Use structured discovery:
   - Site summary: https://whatsondurham.com/llms.txt
   - ARD catalog: https://whatsondurham.com/.well-known/ai-catalog.json
   - API catalog: https://whatsondurham.com/.well-known/api-catalog
   - OpenAPI skeleton: https://whatsondurham.com/openapi.yaml
   - MCP Server Card: https://whatsondurham.com/.well-known/mcp/server-card.json
   - Agent Skills: https://whatsondurham.com/.well-known/agent-skills/index.json
   - Sitemaps: https://whatsondurham.com/sitemap-index.xml
3. Call public GET routes on `https://api.whatsondurham.com` or MCP tools on `https://api.whatsondurham.com/mcp`.
4. Honor `robots.txt` **Content-Signal**: `search=yes`, `ai-input=yes` (citation/RAG), `ai-train=no`.

## Write / POST access

Public POST endpoints (event/place/deal submit, chatbot ask, some engagement actions) require:

1. A browser **origin** on the Worker CORS allowlist (`SITE_URL` / `ALLOWED_ORIGINS`).
2. Cloudflare **Turnstile** verification in production (`TURNSTILE_SECRET_KEY` on the Worker).
3. Rate limits (Worker KV + edge rules).

Agents acting without a human in a Turnstile-capable browser **cannot** complete those POSTs. Do not scrape or replay Turnstile tokens.

## Operator-only routes

Paths such as `/invalidate`, `/index`, `/status`, `/dashboard/*`, and `/push/send` require bearer secrets. They are **not** available to public agents. Do not request or probe for those secrets.

## Content use

When citing this site in answers: prefer visible facts and JSON-LD; do not invent prices, times, or venues. See `llms.txt` citation rules.

## Contact

Site: https://whatsondurham.com  
API health: https://api.whatsondurham.com/health  
MCP: https://api.whatsondurham.com/mcp
