Files
microfish/docs/engineering-log/2026-09-01-auth-secret-key.md
Kunthawat Greethong 91beb8c2dc fix: fail fast on missing/short SECRET_KEY; hide ADMIN_PASSWORD from argv
Production correct-credential login returned auth_unavailable 503 because
Flask's SECRET_KEY was unset: wrong-password probes stopped at 401 before
CSRF token issuance, while valid credentials reached _csrf_serializer()
and crashed. App factory now rejects absent/short (<32 char) SECRET_KEY at
startup, and docker_entrypoint.sh fails fast before migration/services.
Bootstrap no longer passes ADMIN_PASSWORD in process arguments; env-only.

Tests: app-factory + entrypoint regression (5 focused passed), full
backend suite 204 passed. Independent review PASS.
2026-09-01 16:28:04 +07:00

2.0 KiB

2026-09-01 — Login 503 from Missing SECRET_KEY

Status

Root cause proved; fail-fast fix implemented and verified locally; fresh review pending.

Incident

Production login returned:

{"error_code":"auth_unavailable","success":false}

Wrong-password probes returned 401, while the browser's correct credentials returned 503. The distinction was critical: invalid credentials exit before session/CSRF issuance, but successful credential verification continues to issue_csrf_token().

Verified root cause

Config.SECRET_KEY reads the SECRET_KEY environment variable. issue_csrf_token() calls _csrf_serializer(), which raises ApiError("auth_unavailable", 503, ...) when current_app.secret_key is absent. Therefore the browser's 503 indicates that credentials passed but the deployment had no signing secret.

Fix

  • create_app() now raises RuntimeError("secret_key_required") when the signing secret is absent.
  • docker_entrypoint.sh now fails before migration/services if SECRET_KEY is absent or shorter than 32 characters, with a clear error message.
  • Bootstrap now reads ADMIN_PASSWORD only from inherited environment variables; it is no longer exposed in process arguments.
  • Added RED/GREEN app-factory and entrypoint security regression tests.

Verification

  • RED: the missing-secret test failed because create_app() previously started normally.
  • GREEN: focused app-factory/entrypoint security tests 5 passed.
  • Backend full suite 204 passed, 24 warnings.
  • Entry-point Bash syntax passed.
  • git diff --check passed.
  • Independent reviewer (CEO profile): {"passed":true,"security_concerns":[...],"logic_errors":[],"suggestions":[...]}.

Operator action

Generate a persistent random signing secret (for example python3 -c "import secrets; print(secrets.token_urlsafe(48))"), save it as the EasyPanel SECRET_KEY environment variable, set SESSION_COOKIE_SECURE=true, and restart/redeploy. Do not rotate SECRET_KEY casually because existing sessions and encrypted platform settings depend on it.