authentication
route access, api keys, and session auth
authentication
default: all unmatched routes require auth. GET routes default to public.
public access
all GET endpoints are public — no auth needed.
the following POST routes are also public:
| method | route |
|---|---|
| POST | /embed/*/encrypt |
| POST | /embed/*/decrypt |
| POST | /tools/*/execute |
everything else — any POST, PUT, PATCH, DELETE not listed above — requires authentication.
api key
pass an api key via the X-API-Key header:
curl -H "X-API-Key: sk_your_key" gnu.foo/internal/render/mermaidkeys are stored in kv with scopes and a userId. invalid keys return 401.
session
better auth handles session-based auth at /api/auth. supports cookie and bearer token via the bearer plugin.
if no api key is present, the middleware checks for an active session. no session on a protected route returns 401.
protected routes
| method | route | rate limit |
|---|---|---|
| POST | /internal/render/mermaid |
10/60s |
| POST | /internal/layout/elk |
50/60s |
these are the only explicitly protected routes with rate limits. any other non-public route also requires auth but has no per-route rate limit — just the global baseline.
middleware order
auth runs before rate limiting — failed auth doesn't count against your rate limit.
excluded from auth middleware entirely: /api/auth/*, /_admin/*.
errors
{
"type": "https://api.gnu.foo/errors/unauthorized",
"title": "unauthorized",
"status": 401,
"detail": "authentication required for this endpoint",
"_links": { "self": { "href": "/path" } }
}