Tune Security Settings¶
This page covers the security-related toggles and environment variables operators tune most often: CSRF, session cookies, HTTPS and HSTS, and token encryption at rest.
How does CSRF protection work?¶
The SPA uses a double-submit cookie. The server-side validation compares the
x-csrf-token header against the cookie value. The SPA fetches the token
once from GET /api/auth/csrf-token on startup and stores it in a
module-level memory cache; mutations send it in the x-csrf-token header.
| Variable | Default | Notes |
|---|---|---|
CSRF_HTTP_ONLY |
true |
Default changed in v0.35. The SPA does not read the cookie directly; the httpOnly flag removes the token from the XSS-accessible cookie surface. Set false only for a custom client that needs document.cookie access. |
CSRF_SAME_SITE |
strict |
Cookie SameSite policy |
CSRF_SECURE |
true |
Set false only for plain HTTP development |
CSRF_COOKIE_NAME |
bt_csrf_token |
Useful for multi-app deployments |
How is the session cookie configured?¶
bt_session is always HTTP-only and SameSite strict. Secure behavior is
selected in this order:
- Explicit
COOKIE_SECURE=true|false - Explicit
HTTPS=true|false - Whether the current request appears to use HTTPS
How do I enable HTTPS and HSTS?¶
Set HTTPS=true in a production HTTPS deployment to enable HSTS. When TLS
terminates at a reverse proxy, forward X-Forwarded-Proto: https.
How are secrets encrypted at rest?¶
SimpleFIN secrets, SMTP passwords, OIDC client secrets, TOTP secrets and
recovery codes, push notification tokens, and login-history IP/UA/location
columns are all encrypted at rest with AES-256-GCM (HKDF-SHA-256 with the
bill-tracker-token-encryption-v1 info label).
By default, BillTracker generates a stable 48-byte key on first startup and
persists it in the settings table under _auto_encryption_key. For an
operator-managed override, set a value of at least 32 bytes:
Generate one with:
Database key vs env key trade-off
The auto-generated database key is co-located with the ciphertext it
protects — anyone with database read access has everything needed to
decrypt. Set TOKEN_ENCRYPTION_KEY in production to keep the key
separate from the data.
When TOKEN_ENCRYPTION_KEY is set, all DB-key-encrypted secrets are
transparently re-encrypted with the env key in a single transaction on first
startup (prefix e2:; already-e2: values are skipped). The Admin → Bank
Sync card surfaces which key source is currently active.
Keep an override stable across restarts and protect it separately from database backups.
See also¶
- Profile and Login Privacy — user login geolocation, login history, and WebAuthn enrollment
- Run It Day to Day — operator checklist, status page, and incident response
- Security model — the full threat model and deployment checklist
- API Reference (v0.37) — profile privacy and WebAuthn endpoint tables