Security & Access
Authentication model, roles, cookies and isolation.
Security rests on three decisions: short-lived tokens in HttpOnly cookies, middleware-enforced workspace scoping, and least-privilege roles.
Authentication model
Sign-in issues two JWTs. The access token lives for five minutes; the refresh token lives for seven days and is rotated on every use, with the previous value blacklisted.
| Field | Type | Description |
|---|---|---|
| Access token | string | 5 minute lifetime. Sent automatically with API calls. |
| Refresh token | string | 7 day lifetime. Exchanged for a new pair when the access token expires. |
| Rotation | string | On refresh, a new refresh token is issued and the old one is blacklisted. |
| Revocation | string | Signing out blacklists the refresh token and clears both cookies. Completing a password reset revokes every outstanding token for the account. |
Why cookies, not local storage
Tokens are stored in HttpOnly, SameSite=Lax cookies and marked Secure in production. JavaScript — and therefore any cross-site scripting payload — cannot read them. The only value kept in browser storage is the non-sensitive tenant_id.
Tenant isolation
Middleware resolves the active workspace on every request and attaches it to the request object. Querysets are filtered against that workspace, so an opaque identifier from another workspace returns an empty result rather than a leak.
Authorisation
Four roles are supported — admin, editor, analyst and viewer. Destructive operations require an admin, and every write is attributed to the authenticated user.
Deployment hardening
- Set a strong
SECRET_KEYfrom the environment; never commit it. - Turn
DEBUGoff and restrictALLOWED_HOSTS. - Serve only over TLS so
Securecookies are enforced. - Point
CORS_ALLOWED_ORIGINSandCSRF_TRUSTED_ORIGINSat your real frontend origin. - Use PostgreSQL rather than SQLite for concurrent production traffic.
- Rotate database, broker and storage credentials on a schedule.
Last reviewed October 2026.