Auth production checklist
A pre-flight specifically for the authentication surface. The broader Production checklist includes this plus the rest (rate limits, single-worker, signed artifacts, health probes).
Before exposing the API
-
At least one credential exists. Either:
- Set
SECURESCAN_API_KEYto a strong random string (e.g.openssl rand -hex 32); OR - Create a DB-backed admin key via
POST /api/v1/keys(see API keys).
- Set
-
SECURESCAN_AUTH_REQUIRED=1is set. Without it, dev-mode fallback applies if all credentials are removed (silent unauthenticated state). With it, the backend exits with code 2 at startup if no credentials exist — fail-closed. -
SECURESCAN_EVENT_TOKEN_SECRETis set (required whenAUTH_REQUIRED=1). Without it, every backend restart breaks in-flight SSE tokens. See SSE event tokens.
# Suggested env-var generation (Linux / macOS)
export SECURESCAN_AUTH_REQUIRED=1
export SECURESCAN_EVENT_TOKEN_SECRET="$(openssl rand -hex 32)"
# Either keep the legacy env-var key as a break-glass...
export SECURESCAN_API_KEY="$(openssl rand -hex 32)"
# ...or rely on DB keys exclusively (post-migration).
DB key issuance
-
Issue at least one admin key via the API or the dashboard
before turning off
SECURESCAN_API_KEY. Otherwise revoking the last admin key would lock you out — lockout protection catches the symmetric case but not "operator manually removed env var." -
One admin key, scoped down per consumer. A CI runner gets
["read", "write"]. A monitoring dashboard gets["read"]. Only the operator's break-glass identity getsadmin. - Save the secret to your secrets manager immediately. The plaintext is returned exactly once.
-
Document key ownership. Set
nameto something identifiable (ci-runner,read-only-monitoring,breakglass-2026q2). When you list keys later, you'll be able to tell which is which.
Network exposure
- Terminate TLS in front of SecureScan. The bundled uvicorn serves plain HTTP. nginx, Traefik, AWS ALB, or Caddy are all reasonable.
-
Forward
X-Request-IDthrough the proxy so client correlation works end-to-end. -
Restrict access to
/docs,/redoc,/openapi.jsonif your threat model includes "an unauthenticated actor learning the API surface." These describe every route — including admin — but expose no data. For most internal deployments, leaving them open to authenticated network paths is fine.
SecureScan does not ship its own SSO / OIDC integration. If you
need user-mapped auth, put it in front of SecureScan (oauth2-proxy,
Cloudflare Access, AWS ALB OIDC) and treat the backend as a service
that authenticates via API keys. The dashboard's
NEXT_PUBLIC_SECURESCAN_API_KEY is then a service identity for the
proxy, not a user identity.
Frontend wiring
-
NEXT_PUBLIC_SECURESCAN_API_KEYis aread-scope key, not admin. The value is baked into the build and shipped to the browser. Anyone who can hit the dashboard can read its key off the network tab. Only deploy the dashboard somewhere already protected by your front-line auth (SSO, mTLS). -
The dashboard is not exposed publicly. If it is, every
visitor automatically has
read(and any other scope you scoped it to) on the backend. That's a deliberately simple model — keep it inside your network perimeter.
Operational
- Rotation procedure documented. Know in advance how to issue a new key and revoke an old one. See API keys → Lifecycle: rotate a key.
-
Alarm on auth failures. Tail the structured logs for
securescan.requestlines withstatus: 401and graph them. A spike past your normal noise floor means something has gone wrong (key expired, brute-force attempt, misconfigured caller). -
Periodic key audit.
GET /api/v1/keyslists every key withlast_used_at. Anything not used in 90 days is a candidate for revocation.
SSE / real-time progress
-
SECURESCAN_EVENT_TOKEN_SECRETis set and stable across restarts. Rotating this secret invalidates every outstanding event token; your dashboard's live progress will go blind for ~5 minutes while clients re-mint. -
Run
--workers 1. The event bus is in-process; multi-worker uvicorn fragments the bus and SSE breaks silently. See Single-worker constraint. -
Sticky sessions on
scan_idif you scale horizontally. Each scan's SSE subscribers must land on the same backend instance that runs the scan.
Incident response
-
Revoke a leaked key immediately.
DELETE /api/v1/keys/{id}takes effect on the next request. No cache, no propagation delay. -
Rotate
SECURESCAN_EVENT_TOKEN_SECRETif an event token was specifically leaked. All outstanding tokens become invalid; legitimate clients re-mint within seconds. -
SECURESCAN_API_KEYrotation requires a backend restart. The env-var path reads on every request, but a hot rotation means the new value isn't picked up until the process restarts. To do a zero-downtime rotation, issue a DB key first, switch the consumer, then update / restart.
Verifying a deployment is hardened
# 1. Auth is required:
$ curl -i http://127.0.0.1:8000/api/v1/scans
HTTP/1.1 401 Unauthorized
{"detail":"X-API-Key header required"}
# 2. Bogus key 401s (does not fall through to dev mode):
$ curl -i -H "X-API-Key: nope" http://127.0.0.1:8000/api/v1/scans
HTTP/1.1 401 Unauthorized
{"detail":"Invalid API key"}
# 3. Read-only key cannot create a scan:
$ curl -i -X POST -H "X-API-Key: $READ_KEY" \
-d '{"target_path":"/tmp","scan_types":["code"]}' \
http://127.0.0.1:8000/api/v1/scans
HTTP/1.1 403 Forbidden
{"detail":"Requires scope: write"}
# 4. Write key cannot list webhook subscriptions:
$ curl -i -H "X-API-Key: $WRITE_KEY" http://127.0.0.1:8000/api/v1/webhooks
HTTP/1.1 403 Forbidden
{"detail":"Requires scope: admin"}
# 5. /health and /ready are public:
$ curl -s http://127.0.0.1:8000/health
{"status":"ok"}
# 6. Lockout protection refuses removing the last admin key:
$ curl -i -X DELETE -H "X-API-Key: $ADMIN_KEY" \
http://127.0.0.1:8000/api/v1/keys/$ONLY_ADMIN
HTTP/1.1 409 Conflict
{"detail":"Cannot revoke last admin key without an env-var fallback"}
If those six are green, the auth surface is correctly configured.
Next
- API keys — issuance, rotation, lockout protection.
- Scopes — what each scope grants, route by route.
- SSE event tokens — auth on the live stream.
- Production checklist — the broader pre-flight.