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.

FieldTypeDescription
Access tokenstring5 minute lifetime. Sent automatically with API calls.
Refresh tokenstring7 day lifetime. Exchanged for a new pair when the access token expires.
RotationstringOn refresh, a new refresh token is issued and the old one is blacklisted.
RevocationstringSigning 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_KEY from the environment; never commit it.
  • Turn DEBUG off and restrict ALLOWED_HOSTS.
  • Serve only over TLS so Secure cookies are enforced.
  • Point CORS_ALLOWED_ORIGINS and CSRF_TRUSTED_ORIGINS at 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.