Goal
Let surface Workers (rafters, eavesdrop, mail, ctrl) call /api/uncertainty/predictions and /api/uncertainty/predictions/:id/witness without a user session. They are services, not users; requireAuth middleware blocks them today.
Approach
Wire the better-auth api-key plugin into apps/web/src/auth.ts (same shape as planned for the meter PR series, issue #135). Keys are org-scoped, opaque random (no signature inside -- per legion 019e6514 doctrine), revocable via enabled flag.
Permission vocabulary:
- uncertainty:emit -- POST /predictions
- uncertainty:witness -- PUT /predictions/:id/witness
- uncertainty:read -- GET /calibration, GET /orphans
Routes change:
- Replace requireAuth on /api/uncertainty/* with a mixed middleware that accepts EITHER user session (admin/debug) OR api-key with required permission for that route
- Each route declares its required permission
One api-key per surface, minted manually for v0 (e.g. rafters-color-naming gets uncertainty:emit + uncertainty:witness). Later automate via ctrl.
Out of Scope
- @rafters/uncertainty-client extraction (design doc says later, after >1 surface adopts)
- Service binding alternative (worth revisiting if latency budget tightens)
- Auto-minting from ctrl
Done When
Context
Goal
Let surface Workers (rafters, eavesdrop, mail, ctrl) call /api/uncertainty/predictions and /api/uncertainty/predictions/:id/witness without a user session. They are services, not users; requireAuth middleware blocks them today.
Approach
Wire the better-auth api-key plugin into apps/web/src/auth.ts (same shape as planned for the meter PR series, issue #135). Keys are org-scoped, opaque random (no signature inside -- per legion 019e6514 doctrine), revocable via enabled flag.
Permission vocabulary:
Routes change:
One api-key per surface, minted manually for v0 (e.g. rafters-color-naming gets uncertainty:emit + uncertainty:witness). Later automate via ctrl.
Out of Scope
Done When
Context