# auth.md

Agent authentication for **Kemeny Studio** (`https://kemenystudio.com`).

## Audience

Buyer-facing coding agents, browser agents, and A2A clients that need company facts, the public offer catalog, case studies, or to file a quote intent.

Internal ecosystem apps that read ICP definitions from `/api/icp` are a separate audience.

## Public buyer APIs — no token

These endpoints are **tokenless**. Do not start an OAuth or OIDC flow for them.

| Surface | URL | Auth |
| --- | --- | --- |
| HTTP MCP | https://kemenystudio.com/api/mcp | none (rate-limited) |
| A2A JSON-RPC | https://kemenystudio.com/api/a2a | none (rate-limited) |
| REST overview | https://kemenystudio.com/api/agent/overview | none |
| REST cases | https://kemenystudio.com/api/agent/cases | none |
| REST recommend | https://kemenystudio.com/api/agent/recommend | none |
| REST quote intent | https://kemenystudio.com/api/agent/quote-request | none (rate-limited write) |
| WebMCP | `document.modelContext.registerTool` on https://kemenystudio.com | none; quote writes wait for the visitor to confirm |

Rate limits: 60 reads/minute and 8 quote writes/minute per client IP.

## How to register (buyer)

Buyer agents are already allowed. Do not start ID-JAG, email-claim, or a sign-up form.

Discovery:

1. `GET https://kemenystudio.com/.well-known/oauth-protected-resource` — RFC 9728 (`resource`, `authorization_servers`, `scopes_supported`, `bearer_methods_supported: ["header"]`).
2. `GET https://kemenystudio.com/.well-known/oauth-authorization-server` — RFC 8414 plus `agent_auth` (`skill`, `register_uri`, `identity_types_supported: ["anonymous"]`).
3. Optional: `POST https://kemenystudio.com/api/oauth/agent-auth` with `{ "type": "anonymous" }`. That confirms the policy. It does **not** issue a token or an API key.

There is no claim ceremony and no revocation URL. `identity_assertion` (ID-JAG) and `service_auth` return `unsupported_identity_type`.

A buyer agent is already allowed to:

1. Read `GET https://kemenystudio.com/api/mcp` or `initialize` over JSON-RPC.
2. Call read tools without credentials.
3. Call `request_quote` / `POST /api/agent/quote-request` with the buyer's work email. That files a CRM lead. It does **not** issue an API key and does **not** return a firm price.

Install:

```bash
npx -y add-mcp https://kemenystudio.com/api/mcp -g
npx skills add KemenyStudio/kemenystudiolanding
```

## ICP API — OAuth 2.0 client_credentials

`GET https://kemenystudio.com/api/icp` is for other Kemeny apps (not public buyer agents). Discovery:

- RFC 8414: https://kemenystudio.com/.well-known/oauth-authorization-server
- OIDC path (same document; this server is not an OpenID Provider): https://kemenystudio.com/.well-known/openid-configuration
- Protected resource (RFC 9728): https://kemenystudio.com/.well-known/oauth-protected-resource — `resource` is https://kemenystudio.com; `authorization_servers` is that same issuer; scope `icp.read`

`grant_types_supported` is `client_credentials` only. The authorization endpoint does not issue codes and never redirects to a `redirect_uri`.

```bash
curl -s -X POST https://kemenystudio.com/api/oauth/token \
  -u kemeny-studio-icp:$ICP_SERVICE_API_KEY \
  -d grant_type=client_credentials \
  -d scope=icp.read
```

Use the returned `access_token` as `Authorization: Bearer`. The same pre-provisioned key still works directly as `x-api-key` or Bearer (opaque token). Keys are issued by Kemeny Studio to named consumers. Request one at contacto@kemenystudio.com with the consuming app name. Unauthenticated requests return 401 with `WWW-Authenticate` pointing at the protected-resource metadata.

`jwks_uri` is published and returns an empty JWK Set because access tokens are opaque, not JWTs.

## Admin and cron

`/admin`, CMS, and cron routes are not agent registration surfaces. Do not probe them.

## Credential use

- Buyer MCP / REST / A2A: send no Authorization header.
- ICP: send the issued key on every request, or exchange it at `/api/oauth/token` first.
- x402 / MPP brief: no API key. Unpaid `GET https://kemenystudio.com/api`, `GET https://kemenystudio.com/api/v1`, or `GET https://kemenystudio.com/api/x402/brief` returns HTTP 402 with `PAYMENT-REQUIRED` (x402) and `WWW-Authenticate: Payment` (MPP). Retry with `PAYMENT-SIGNATURE` or `Authorization: Payment`. Catalog: https://kemenystudio.com/.well-known/x402.json. OpenAPI `x-payment-info` on those operations.
- Never put keys in query strings. Page paths that did were redacted at write time.

## x402 / MPP micropayment (optional)

`GET https://kemenystudio.com/api`, `GET https://kemenystudio.com/api/v1`, and `GET https://kemenystudio.com/api/x402/brief` are the paid HTTP resources (same micropayment). Buyer MCP, A2A, and other `/api/*` routes stay tokenless.

This is a per-request USDC payment on Base, not a consulting quote and not an OAuth grant. A 402 here does **not** mean the rest of the site is paywalled. The brief still never returns a firm Kemeny price. Discovery: OpenAPI `x-payment-info` (intent `charge`, method `tempo`) and https://kemenystudio.com/.well-known/x402.json.

## Universal Commerce Protocol (catalog, not checkout)

Profile: https://kemenystudio.com/.well-known/ucp. Catalog search: https://kemenystudio.com/api/ucp/catalog/search (GET or POST, tokenless). This advertises `dev.ucp.shopping.catalog.search` only. There is no UCP checkout. Firm prices still come from a human after the Workflow Fit Check.

## Agentic Commerce Protocol (discovery, not a cart)

Discovery: https://kemenystudio.com/.well-known/acp.json. REST base: https://kemenystudio.com/api/acp. This document exists so agents can find the commerce API without opening a checkout session. `POST https://kemenystudio.com/api/acp/checkout_sessions` does not create a session and never returns a firm price. Use Fit Check, then `request_quote`.

## Pricing

Firm prices are quoted by a human after conversation, usually after the Workflow Fit Check (https://kemenystudio.com/ai-workflow-fit-check). Market ranges on the site are planning figures only.
