# Authentication for agents — robskan.nl

How automated clients should access robskan.nl resources.

## Discover

Protected API namespace: `https://robskan.nl/api`

Public read APIs (no credentials):

- `GET /api/v1/health` — API health and OpenAPI discovery
- `GET /api/v1/profile` — name, links, decimal age
- `GET /api/v1/music/now-playing` — Spotify snapshot
- `GET /api/v1/music/listening-summary` — recent/top summary
- Legacy: `/api/get/spotify`, `/api/get/spotify/stream`
- **Owner Spotify OAuth** under `/api/spotify/*` is for human session setup only — do not drive it from agents.

Machine-readable metadata:

- Resource metadata (RFC 9728): `https://robskan.nl/.well-known/oauth-protected-resource`
- Authorization server (RFC 8414): `https://robskan.nl/.well-known/oauth-authorization-server`
- Human + agent prose: this file (`/auth.md`)

<!-- agent_auth
identity_endpoint: https://robskan.nl/agent/identity
identity_types_supported:
  - anonymous
  - service_auth
service_auth:
  methods_supported:
    - none
identity_assertion:
  assertion_types_supported: []
agent_auth:
  skill: https://robskan.nl/auth.md
-->

## Pick a method

| Method | When |
|--------|------|
| **anonymous** | Public GET endpoints (`/api/v1/*` read routes, `/api/get/*`, lyrics, markdown, MCP read tools) |
| **service_auth** | Not required today — no API keys issued for this personal site |
| **identity_assertion** | Not supported |

## Register

No agent registration is required for anonymous public reads.

## Claim

Not applicable — no delegated agent accounts on this site.

## Exchange

Not applicable for anonymous access.

## Use the access_token

Send unauthenticated `GET` requests to documented public routes. Example:

```http
GET /api/v1/profile HTTP/1.1
Host: robskan.nl
```

## Errors

All `/api/v1/*`, `/ask`, and documented `/api/get/*` proxy routes return **JSON** (`application/problem+json`) errors with fields:

- `code` — machine-readable error id (e.g. `rate_limited`, `not_found`)
- `title`, `detail`, `status`, `type` — RFC 9457-style problem details
- `hint` — optional resolution guidance for agents

Examples:

- `401` on `/api/v1` includes `WWW-Authenticate: Bearer resource_metadata="https://robskan.nl/.well-known/oauth-protected-resource"` — read that JSON before retrying protected namespaces.
- `429` — back off using `Retry-After`.
- Unknown `/api/v1/...` paths return `404` with `code: not_found`.

## Idempotency

These **POST** endpoints accept an **`Idempotency-Key`** header for safe retries (24h TTL, in-memory per server instance):

- `POST /ask`
- `POST /api/v1/batch`
- `POST /api/v1/jobs/nlweb-query`

Repeat the same key with an identical body to receive the cached response instead of creating duplicate work. Discovery: `GET /api/v1/health` includes an `idempotency` object; OpenAPI declares the header on each POST operation.

## Sandbox

- **Sandbox:** `GET /api/v1/sandbox` returns verified sandbox metadata (`testMode`, endpoint map).
- **Health:** `GET /api/v1/health` confirms the public API surface is reachable.

## Endpoints (discovery)

| URI | Purpose |
|-----|---------|
| `OPTIONS https://robskan.nl/agent/identity` | Agent identity capability probe |
| `OPTIONS https://robskan.nl/agent/auth/claim` | Claim flow probe (not used) |
| `OPTIONS https://robskan.nl/agent/auth/events` | Events probe (not used) |
