# auth.md — Dike API authentication

Dike's REST and gRPC APIs use static Bearer API keys — there is no OAuth/OIDC flow.

## Getting a key

**Signup is currently closed for testing.** `POST /account/signup` exists and
is documented below for when it reopens; while closed it returns
`403 signup_closed`. Until then, request a key at
https://dike.it.com/developers/ and one is issued to your account manually.

## Agent registration (self-serve, once signup reopens)

This is a real API, not a manual process — but it is not a fully autonomous
"zero human in the loop" registration, by design: step 2 requires a human (or
an agent acting with a human's mailbox access) to click a real verification
link. This is an intentional abuse-prevention control, not a limitation
we're planning to remove.

1. **Create the account**
   ```bash
   curl -X POST https://api.dike.it.com/account/signup \
     -H "Content-Type: application/json" \
     -d '{"email": "you@example.com", "password": "at least 8 characters"}'
   ```
   Returns `201` with `{"id", "email", "email_verified": false}`, or `409
   email_taken` if the email is already registered.

2. **Verify the email** — a verification link is emailed to the address
   above; the human (or agent with mailbox access) follows it, which hits:
   ```
   GET https://api.dike.it.com/account/verify?token=<from the email>
   ```

3. **Log in** to get a JWT (this token authenticates the account-management
   endpoints below — it is NOT the API key used for `/v1/*` and MCP calls):
   ```bash
   curl -X POST https://api.dike.it.com/account/login \
     -H "Content-Type: application/json" \
     -d '{"email": "you@example.com", "password": "..."}'
   ```
   Returns `{"token": "<jwt>"}`.

4. **Create an API key**, authenticated with that JWT:
   ```bash
   curl -X POST https://api.dike.it.com/account/keys \
     -H "Authorization: Bearer <jwt from step 3>" \
     -H "Content-Type: application/json" \
     -d '{"label": "my agent"}'
   ```
   Returns `201` with `{"id", "label", "key", "key_prefix", "created_at"}` —
   `key` is the actual API key (the `Bearer` token for `/v1/*` and MCP calls
   below) and is shown exactly once; it is never retrievable again after this
   response.

`GET /account/me`, `GET /account/keys`, `DELETE /account/keys/:id`,
`GET /account/usage`, and `GET /account/quota` (all JWT-authenticated) round
out self-service account management once a key exists.

## Using a key

Send it as a standard Bearer token on every request:

```
Authorization: Bearer $DIKE_API_KEY
```

Base URL: `https://api.dike.it.com`

Example:

```bash
curl -X POST https://api.dike.it.com/v1/search \
  -H "Authorization: Bearer $DIKE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query": "مسؤولية الناقل الجوي عن تأخير الرحلات", "top_k": 10}'
```

The same key authenticates the gRPC mirror (`api.dike.it.com:9090`) via the
`authorization: Bearer <api_key>` gRPC metadata entry, and the MCP server
(`https://api.dike.it.com/mcp`, Streamable HTTP) via the same
`Authorization: Bearer` header on every JSON-RPC request.

## Rate limits

Default: 60 requests/minute per key. `/v1/reason` and the `dike_reason` MCP
tool (the grounded reasoning endpoint — same limit, tracked separately per
transport): 10 requests/minute per key.

## Full API reference

- OpenAPI spec: https://api.dike.it.com/v1/openapi.yaml
- API catalog (RFC 9727): https://dike.it.com/.well-known/api-catalog
- MCP server card: https://dike.it.com/.well-known/mcp/server-card.json
- Interactive docs: https://dike.it.com/developers/
