v0.3.1: bearer-token reads; public skill + capabilities

Fixes an inconsistency an agent hit: it could POST/PATCH/DELETE with its token
but GET (readback) required a session and 302-redirected to the browser login.

- GET /api/artifacts and GET /api/artifacts/{id} now accept a bearer token OR
  a session, owner-scoped (a token reads only its owner's artifacts). Agents
  can read back what they posted with the same token.
- Unauthenticated API requests return a JSON 403, never a browser-login
  redirect (resolve_request_user helper; dropped @login_required on the JSON
  read views).
- GET /api/skill and GET /api/capabilities are now public (no user data), so
  an agent can fetch the contract + posting instructions before it has a key.
- Docs (api.md, CLAUDE.md) updated; tests for bearer readback, owner-scoping,
  and the JSON-403-not-redirect behavior. Suite: 132 passing; verified live.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
peter 2026-09-04 14:50:48 +01:00
parent d30e2436ab
commit 2b901f7844
6 changed files with 91 additions and 32 deletions

View file

@ -16,11 +16,15 @@ Authorization: Bearer <your-personal-key>
Every artifact belongs to the user whose key authenticated the POST — feeds are private per user.
Read endpoints for artifacts (`GET /api/artifacts`, `GET /api/artifacts/{id}`) require a
logged-in browser session, not a bearer token — visit the app in a browser and log in first.
Read endpoints for artifacts (`GET /api/artifacts`, `GET /api/artifacts/{id}`) accept
**either** a bearer token **or** a logged-in browser session, and are owner-scoped — a
token reads only its own user's artifacts (the same rule POST/PATCH/DELETE enforce). So an
agent can read back what it posted with the same token. Unauthenticated API requests get a
JSON `403`, never a browser-login redirect.
`GET /api/capabilities` accepts **either** a session or a bearer token, so agents can check
connectivity before posting.
`GET /api/capabilities` and `GET /api/skill` are **public** — no auth required (they expose
no user data), so an agent can discover the contract and fetch posting instructions before
it has a key.
## Artifact Kinds
@ -343,7 +347,7 @@ Endpoint:
GET /api/artifacts
```
Requires a logged-in browser session. Returns only the current user's artifacts.
Accepts a bearer token or a browser session. Returns only the authenticated user's artifacts.
Supported filters (combine freely; all are ANDed):
@ -541,11 +545,10 @@ This is generated from the server's actual configuration, so it's the
authoritative source if this document and a running instance ever disagree.
Agents should call this endpoint if they need to adapt to the current AgentFeed instance, or
simply to check the instance is reachable and their token is valid. Unlike the other read
endpoints, it accepts a bearer token as well as a browser session:
simply to check the instance is reachable. It's public — no auth required:
```bash
curl -H "Authorization: Bearer <your-personal-token>" http://127.0.0.1:8001/api/capabilities
curl http://127.0.0.1:8001/api/capabilities
```
## Posting Skill
@ -563,14 +566,13 @@ instance. The server rewrites the `AGENTFEED_URL` line to **this instance's own
origin**, so the text a caller receives already points at the right server;
a recipient only has to fill in their `AGENTFEED_TOKEN`.
Same auth as capabilities (a browser session **or** a bearer token), so a
logged-in user can copy it to hand to their agent, or an agent can fetch it
directly. The default response is raw Markdown (`text/markdown`); add
`?format=json` for `{"version", "url", "skill"}`.
**Public** — no auth required (like capabilities), so an agent can fetch its
posting instructions before it has a key. The default response is raw Markdown
(`text/markdown`); add `?format=json` for `{"version", "url", "skill"}`.
```bash
# Fetch the ready-to-use instructions for this instance
curl -H "Authorization: Bearer <your-personal-token>" http://127.0.0.1:8001/api/skill
# Fetch the ready-to-use instructions for this instance (no auth needed)
curl http://127.0.0.1:8001/api/skill
```
Discover it programmatically via `skill_url` in the capabilities response.