Security¶
CORS Configuration¶
The server restricts cross-origin requests to a whitelist of allowed origins. By default only the FRONTEND_URL is allowed.
| Env var | Default | Description |
|---|---|---|
ALLOWED_ORIGINS |
FRONTEND_URL value |
Comma-separated list of allowed origins |
Origins can also be managed at runtime via Admin > Security Settings in the web UI (settings:manage permission required).
CSRF Protection¶
State-changing requests (POST, PUT, PATCH, DELETE) require a valid CSRF token when cookie-based sessions are active (OIDC enabled).
- On login, the server sets a
floh_csrfcookie (not httpOnly). - The frontend reads this cookie and sends it as the
X-CSRF-Tokenheader on mutating requests. - The server validates that the header matches the cookie value.
- CSRF protection is automatically disabled when OIDC is not configured (dev mode).
API clients using Bearer tokens are not affected by CSRF checks.
Webhook Authentication¶
Connector webhook endpoints require HMAC-SHA256 signature verification.
- Configure a webhook secret on the connector (stored encrypted in the DB).
- The caller computes
HMAC-SHA256(secret, request_body)and sends it as theX-Webhook-Signatureheader. - The server verifies the signature before processing the event.
Requests without a valid signature receive a 401 Unauthorized response.
Rate Limiting¶
The server applies rate limiting via @fastify/rate-limit:
| Scope | Limit | Window |
|---|---|---|
| Global | 200 req | 1 minute |
/api/auth/* |
20 req | 1 minute |
/api/entitlements/webhook/* |
30 req | 1 minute |
Localhost (127.0.0.1, ::1) is excluded from rate limits during development.
Session Security¶
| Property | Value |
|---|---|
| Cookie name | floh_sid |
httpOnly |
true |
secure |
true when FRONTEND_URL starts with https |
sameSite |
lax |
| TTL | 24 hours |
| Encryption | Optional via SESSION_ENCRYPTION_KEY (64-char hex) |
| Storage | Redis with key floh:session:{id} |
Dev Auth Bypass Guard¶
In production (NODE_ENV=production), the server refuses to start if OIDC_ISSUER is not set. This prevents the dev auth bypass from accidentally running in production.
Secret Management¶
The following secrets must be explicitly set in production. The server will refuse to start if any of them use their default/fallback values:
| Secret | Env var | Default (dev only) |
|---|---|---|
| JWT secret | JWT_SECRET |
dev-jwt-secret |
| Database password | DB_PASSWORD |
floh_secret |
| Session secret | SESSION_SECRET |
Same as JWT_SECRET |
| Connector encryption | CONNECTOR_ENCRYPTION_KEY |
Insecure dev key |
| Session encryption | SESSION_ENCRYPTION_KEY |
Unencrypted storage |
Generate encryption keys with:
Error Handling¶
In production, API error responses contain only statusCode, error, and a generic message. Stack traces and internal details are never exposed. In development, stack traces are included when SHOW_ERROR_DETAILS=true.
Production Checklist¶
- [ ]
NODE_ENV=production - [ ]
OIDC_ISSUERis set - [ ]
JWT_SECRETis a strong random value - [ ]
DB_PASSWORDis not the default - [ ]
SESSION_SECRETis a strong random value - [ ]
CONNECTOR_ENCRYPTION_KEYis a 64-char hex key - [ ]
SESSION_ENCRYPTION_KEYis a 64-char hex key - [ ]
AUDIT_CHECKPOINT_KEYis a 64-char hex key - [ ]
ALLOWED_ORIGINSis restricted to known frontend URLs - [ ]
SHOW_ERROR_DETAILS=false - [ ] Rate limiting is enabled