Problem
Several API route groups shipped with no auth middleware, so the global
pass-through authenticate left them effectively public:
usfm — all 5 export/download/job routes (POST /project-units/{id}/usfm,
/usfm/async, GET /usfm/books, GET /jobs/{id}, GET /downloads/{filename}).
Anyone could export/download any organization's translated content.
bibles — full CRUD incl. POST/PATCH/DELETE. Anyone could
create/modify/delete shared source Bibles referenced by every project.
The OpenAPI specs already documented 401, so spec and behaviour had drifted.
Surfaced by a code audit of fluent-web + fluent-api (2026-06-18).
Decision (reviewer, 2026-06-18)
- USFM: a general auth check is sufficient for now.
- Bibles: anyone logged in may read; modification is an admin-only ability →
flat-deny writes until the admin role is introduced.
Scope of this issue (fixed in #189)
denyUntilAdminRole() placeholder middleware (401 if unauthenticated, 403 otherwise).
- Bibles: reads require
authenticateUser; writes flat-denied.
- USFM: all 5 routes require
authenticateUser.
- OpenAPI
responses updated to document 401/403.
Follow-ups (separate — documented in docs/proposals/security-and-export-hardening/)
- USFM project-scoped authorization (export pulls per-project content).
bible-texts / books read-auth decision (intentional anonymous mobile pre-cache?).
- Export error UX + Azure logging;
fluent-web useExportUsfm credentials.
- Async export pipeline hardening; presence-route assignment-level authz.
Problem
Several API route groups shipped with no auth middleware, so the global
pass-through
authenticateleft them effectively public:usfm— all 5 export/download/job routes (POST /project-units/{id}/usfm,/usfm/async,GET /usfm/books,GET /jobs/{id},GET /downloads/{filename}).Anyone could export/download any organization's translated content.
bibles— full CRUD incl.POST/PATCH/DELETE. Anyone couldcreate/modify/delete shared source Bibles referenced by every project.
The OpenAPI specs already documented
401, so spec and behaviour had drifted.Surfaced by a code audit of
fluent-web+fluent-api(2026-06-18).Decision (reviewer, 2026-06-18)
flat-deny writes until the admin role is introduced.
Scope of this issue (fixed in #189)
denyUntilAdminRole()placeholder middleware (401 if unauthenticated, 403 otherwise).authenticateUser; writes flat-denied.authenticateUser.responsesupdated to document 401/403.Follow-ups (separate — documented in
docs/proposals/security-and-export-hardening/)bible-texts/booksread-auth decision (intentional anonymous mobile pre-cache?).fluent-webuseExportUsfmcredentials.