# Chicago Politics auth.md

How AI agents and apps get access to Chicago Politics: the JSON API (`https://www.chicagopolitics.org/api/v1`), the MCP server (`https://www.chicagopolitics.org/mcp`), and the A2A agent (`https://www.chicagopolitics.org/a2a`). All three need a credential tied to a free account. Web pages, their Markdown versions (`.md`), llms.txt, and feeds stay open.

## Audience

AI agents, MCP clients, and developer tools acting for a person who has (or will create) a Chicago Politics account.

## Registration

Three ways to get a credential. Every credential belongs to one person's account and shares that account's limits.

### 1. Agent registration with a verified email (no browser needed)

1. `POST https://www.chicagopolitics.org/agent/auth` with JSON `{"email": "<the person's email>", "agent_name": "<your name>", "agent_uri": "<https URL, optional>"}`.
   The response (202) has `registration_id`, `claim_token`, `claim_uri`, `interval`, and `expires_in` (30 minutes).
2. We email the person a link to approve or deny. Opening it verifies the email; the account is created if it is new.
3. Poll `POST https://www.chicagopolitics.org/agent/auth/claim` with `{"registration_id": "...", "claim_token": "..."}` every `interval` seconds.
   While waiting: 400 `authorization_pending` (or `slow_down`). Then: 200 with `api_key` (shown once), or 400 `access_denied` / `expired_token`.
4. Use the key as `Authorization: Bearer <api_key>`. Revoke it with `POST https://www.chicagopolitics.org/agent/auth/revoke` and the key as the Bearer token.

### 2. OAuth 2.1 (for MCP clients and apps)

Authorization code flow with PKCE (S256), public clients, dynamic client registration (RFC 7591) or a client ID metadata document URL.

- Authorization server metadata: https://www.chicagopolitics.org/.well-known/oauth-authorization-server
- Protected resource metadata: https://www.chicagopolitics.org/.well-known/oauth-protected-resource (also `/mcp`, `/a2a`, `/api` suffixes)
- Scope: `api`. Access tokens last 1 hour; refresh tokens 30 days and rotate on use.
- Unauthenticated calls to `/mcp`, `/a2a`, and `/api/v1` return 401 with a `WWW-Authenticate` header pointing at the resource metadata.

### 3. API key from the website

The person signs in at https://www.chicagopolitics.org/signin (email link) and creates a key under **API keys** on https://www.chicagopolitics.org/account.

## Supported methods

- `identity_assertion` with `verified_email`, issuing an `api_key` (method 1)
- OAuth 2.1 `authorization_code` + PKCE, issuing bearer access tokens (method 2)
- Personal API keys (method 3)

Anonymous access is not offered for the API, MCP, or A2A.

## Credential use

- Send `Authorization: Bearer <credential>` (or `X-API-Key: <key>` for the JSON API). Never put keys in URLs.
- Limits per account: 1,000 requests a day, 50 AI calls a day (AI-written answers), 60 requests a minute. Responses carry `RateLimit-*` headers; `GET https://www.chicagopolitics.org/api/v1/me` shows usage. Over the limit: 429 with `Retry-After`.
- Keys can't read or change a person's follows, positions, or settings, and can't send email.
- People can revoke keys and disconnect apps on https://www.chicagopolitics.org/account.

## Metadata

```json
{
  "agent_auth": {
    "skill": "https://www.chicagopolitics.org/auth.md",
    "register_uri": "https://www.chicagopolitics.org/agent/auth",
    "revocation_uri": "https://www.chicagopolitics.org/agent/auth/revoke",
    "identity_types_supported": [
      "identity_assertion"
    ],
    "identity_assertion": {
      "assertion_types_supported": [
        "verified_email"
      ],
      "credential_types_supported": [
        "api_key"
      ],
      "claim_uri": "https://www.chicagopolitics.org/agent/auth/claim"
    },
    "events_supported": [
      "credential.issued",
      "credential.revoked"
    ]
  }
}
```

Docs: https://www.chicagopolitics.org/developers · OpenAPI: https://www.chicagopolitics.org/api/openapi.json · Contact: hello@chicagopolitics.org
