Skip to content

feat(#1419): P2 Supabase Auth Hooks capture dark login/MFA failures#1473

Merged
Systemsaholic merged 1 commit into
mainfrom
feature/issue-1419-p2-auth-verification-hooks
Jul 5, 2026
Merged

feat(#1419): P2 Supabase Auth Hooks capture dark login/MFA failures#1473
Systemsaholic merged 1 commit into
mainfrom
feature/issue-1419-p2-auth-verification-hooks

Conversation

@Systemsaholic

Copy link
Copy Markdown
Owner

#1419 Phase 2 — capture DARK login/MFA failures at the GoTrue source

Gate: Codex gpt-5.5 xhigh: APPROVE on d86f86b7 (R1 BLOCK → cast-free fix → R2 APPROVE).
Do NOT self-merge — coordinator (1.0) is sole merger.

Problem

Phase 1 (#1420) counts API 401/403 (security.login_failed / security.access_denied) in security_audit_logs. But wrong-password and failed-MFA attempts run entirely inside Supabase GoTrue — they never reach our API, and auth.audit_log_entries is empty in prod. Those failures were dark.

What ships (CODE only — no Supabase config touched)

  • Migration 20260705120000_1419_auth_verification_hooks.sql (journal idx 343): two Postgres Auth Hook functions hook_password_verification_attempt / hook_mfa_verification_attempt. Both are monitoring-only: they record a security_audit_logs row (security.password_failed / security.mfa_failed) only on failure, wrap the INSERT in begin/exception when others then null (fail-open), and ALWAYS return {"decision":"continue"} on both paths — they never reject / rate-limit / block a login. Failure detection is cast-free (event->'valid' = 'false'::jsonb) so a malformed non-boolean valid cannot throw before the always-continue return. Idempotent create-or-replace + role-guarded grants to supabase_auth_admin (INVOKER: usage/execute/insert), execute revoked from anon/authenticated/public.
  • prod-health-monitor.yml Check-4: folds the two hook-sourced events (no ip) into the total brute-force count only — deliberately kept out of the per-IP CTE — surfaced in the detail line; degrade-safe (malformed count → 0, never fails the step).
  • security-audit.types.ts: KNOWN_SECURITY_AUDIT_EVENTS documents the two hook-sourced events (written by the Postgres functions, not the Nest service).
  • Docs: MONITORING.md section + new runbook docs/runbooks/enable-supabase-auth-verification-hooks.md (staging-first, Al-gated Dashboard enablement; plan-tier caveat flagged).

Tests

Foreground SQL assertion test __tests__/1419_auth_verification_hooks.test.sql6/6 pass on Dev: valid=false→continue+1 row; valid=true→continue+0; missing valid→0; fail-open bad-uuid→continue+no throw+0; malformed non-boolean valid→continue+no throw+0 (the R1 fix).

⚠️ Prod enablement is PENDING — staging-first, Al-gated

Shipping the migration creates the functions but does nothing until the hooks are enabled in the Supabase Dashboard (Authentication > Hooks). Follow the runbook: Staging first, verify a deliberate wrong-password + wrong-MFA each land a row AND login still works, confirm the supabase_auth_admin INSERT grant, then Prod with Al's go-ahead. Confirm Auth Hooks are available on our plan tier (may need Pro).

🤖 Generated with Claude Code

@vercel

vercel Bot commented Jul 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
tailfire-client Ready Ready Preview, Comment Jul 5, 2026 2:39pm
tailfire-ota Ready Ready Preview, Comment Jul 5, 2026 2:39pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@Systemsaholic, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 53 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d7d5f7fb-81a8-4013-bc96-e025584134e9

📥 Commits

Reviewing files that changed from the base of the PR and between 96f613d and d33f6fd.

📒 Files selected for processing (7)
  • .github/workflows/prod-health-monitor.yml
  • apps/api/src/security-audit/security-audit.types.ts
  • docs/MONITORING.md
  • docs/runbooks/enable-supabase-auth-verification-hooks.md
  • packages/database/src/migrations/20260705130000_1419_auth_verification_hooks.sql
  • packages/database/src/migrations/__tests__/1419_auth_verification_hooks.test.sql
  • packages/database/src/migrations/meta/_journal.json
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/issue-1419-p2-auth-verification-hooks

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Phase 1 (#1420) counts API 401/403 in security_audit_logs, but wrong-password
and failed-MFA attempts run inside Supabase GoTrue, never hit our API, and
auth.audit_log_entries is empty in prod. This adds two non-blocking, fail-open
Postgres Auth Hook functions that record a security_audit_logs row on failure
at the GoTrue source, plus the Phase-1 alert coverage for them.

- Migration 20260705120000_1419_auth_verification_hooks.sql (idx 343):
  hook_password_verification_attempt + hook_mfa_verification_attempt. Both
  ALWAYS return {"decision":"continue"} (monitoring-only, never block a login)
  and wrap the INSERT in an exception-swallowing block (fail-open). Idempotent
  create-or-replace + role-guarded grants to supabase_auth_admin (INVOKER
  rights: usage/execute/insert), execute revoked from anon/authenticated/public.
- prod-health-monitor Check-4: adds a scalar sub-count of
  security.password_failed + security.mfa_failed (no ip → total-only, kept out
  of the per-IP CTE), factored into the combined total threshold, surfaced in
  the detail line; degrade-safe (malformed count → 0, never fails the step).
- security-audit.types.ts: KNOWN_SECURITY_AUDIT_EVENTS documents the two new
  hook-sourced events (written by the Postgres functions, not the Nest service).
- docs/MONITORING.md section + new runbook enable-supabase-auth-verification-hooks.md
  (STAGING-FIRST, Al-gated Dashboard enablement; plan-tier caveat flagged).
- Foreground SQL assertion test (__tests__/1419_auth_verification_hooks.test.sql):
  valid=false→continue+1 row; valid=true→continue+0 rows; missing valid→0 rows;
  fail-open (bad uuid)→continue+no throw+0 rows. 5/5 pass on Dev.

Ships the CODE only; the Supabase Dashboard hook enablement is NOT touched
(staging-first, Al-gated).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Systemsaholic Systemsaholic force-pushed the feature/issue-1419-p2-auth-verification-hooks branch from d86f86b to d33f6fd Compare July 5, 2026 14:38
@Systemsaholic Systemsaholic merged commit 9f216a5 into main Jul 5, 2026
13 of 19 checks passed
@Systemsaholic Systemsaholic deleted the feature/issue-1419-p2-auth-verification-hooks branch July 5, 2026 14:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant