diff --git a/API.md b/API.md index 0fa26c9..74b9288 100644 --- a/API.md +++ b/API.md @@ -573,7 +573,7 @@ curl -X GET https://api.riotpiao.com/ \ ### Bearer Token (JWT) -All operations except `/healthz` and `/readyz` require authentication. +All operations except `/healthz` and `/readyz` require authentication via Authentik-issued JWT. ```bash curl -H 'Authorization: Bearer ' \ @@ -582,31 +582,76 @@ curl -H 'Authorization: Bearer ' \ ### Obtaining Tokens -**Via Authentik OIDC (human login):** +**Service Account (client_credentials flow):** + +For programmatic access (agents, CI, scripts), use a service account: + ```bash -core auth login --username user@example.com +# Get credentials from k8s secret (once) +CLIENT_ID=$(kubectl -n portfolio get secret portfolio-agent-oidc -o jsonpath='{.data.CLIENT_ID}' | base64 -d) +CLIENT_SECRET=$(kubectl -n portfolio get secret portfolio-agent-oidc -o jsonpath='{.data.CLIENT_SECRET}' | base64 -d) + +# Exchange for access token +TOKEN=$(curl -s -X POST https://authentik.riotpiao.com/application/o/token/ \ + -d "grant_type=client_credentials" \ + -d "client_id=$CLIENT_ID" \ + -d "client_secret=$CLIENT_SECRET" \ + -d "scope=openid profile groups permissions memory" | jq -r '.access_token') + +# Use token +curl -H "Authorization: Bearer $TOKEN" \ + https://api.riotpiao.com/v1/models ``` -**Via service account (programmatic):** -```bash -core mwinit login --username service-account --password secret -export RIOTPIAO_TOKEN=$(cat ~/.talos/.riotpiao-auth) +**Available service accounts:** +- `portfolio-agent` — Portfolio app (memory:read on homelab/portfolio projects) +- `memory-agent` — Memory service internal (memory:* on all projects) -curl -H "Authorization: Bearer $RIOTPIAO_TOKEN" \ - https://api.riotpiao.com/v1/models +**Human login (authorization_code flow):** + +Browser-based OAuth2 via Authentik. Used by web apps, not CLI. + +``` +1. Redirect to: https://authentik.riotpiao.com/application/o/authorize/ + ?client_id=&response_type=code&redirect_uri=&scope=openid+profile+groups+permissions +2. User authenticates +3. Exchange code for token at /application/o/token/ +``` + +### JWT Claims + +Authentik tokens include these custom claims: + +```json +{ + "sub": "hashed-user-id", + "groups": ["homelab-admins", "llm-admins"], + "permissions": ["llm:inference", "llm:read", "llm:write"], + "memory_projects": ["homelab", "portfolio"], + "memory_visibility": "public", + "memory_role": "user" +} ``` ### Capabilities (RBAC) -Tokens embed capabilities in claims. Required capabilities: +The `permissions` claim contains capabilities. Gateway checks these: -- `llm:inference` — `/v1/*` chat/embeddings/rerank -- `workflow:execute` — `/workflow` operations -- `memory:read` — Memory queries -- `memory:write` — Memory ingest -- `sqs:access` — Queue operations -- `s3:access` — S3 operations -- `iam:admin` — IAM management +| Capability | Required for | Granted to | +|------------|--------------|------------| +| `llm:inference` | `/v1/chat/completions`, `/v1/embeddings`, `/v1/rerank` | llm-admins, llm-users | +| `memory:read` | Memory queries | memory-users, memory-writers, poimen-memory-admins | +| `memory:write` | Memory ingest | memory-writers, poimen-memory-admins | +| `memory:admin` | Memory admin ops | poimen-memory-admins | +| `*` | Everything | homelab-admins | + +**Memory-specific claims:** + +| Claim | Description | +|-------|-------------| +| `memory_projects` | Projects user can access (`["*"]` = all) | +| `memory_visibility` | Max visibility level (`public`, `private`) | +| `memory_role` | Role for memory service (`user`, `admin`, `portfolio-agent`) | ---