Skip to content

[Gap-Audit] auth_audit_logs sign_up events not written for all signup paths #49

@TortoiseWolfe

Description

@TortoiseWolfe

Summary

The admin dashboard's get_security_metrics() function reports signups_this_month as the count of auth_audit_logs rows where event_type = 'sign_up' (monolithic migration line 752). The metric reads from a table that not every signup path writes to, so the dashboard underreports.

Surfaced while verifying #44 (commit 6533567): a test asserted ≥2 audit_log rows from "signup events from user creation" and failed because admin-API createUser() produced zero such rows. Fixing that test was correct, but the underlying instrumentation gap is real.

What's shipped

  • src/lib/auth/audit-logger.tslogAuthEvent() library function
  • src/services/auth/audit-logger.tsAuditLogger.logSignUp(), logSignIn() service class
  • Email/password SignUpForm.tsx:11 calls logAuthEvent on successful submit
  • auth_audit_logs table + RLS policies + get_security_metrics() consumer (line 748)
  • Existing on_auth_user_created AFTER INSERT ON auth.users trigger calls create_user_profile() (line 425)

Gap

event_type = 'sign_up' rows are not written for:

  1. OAuth signupsauth.signInWithOAuth() redirects don't go through SignUpForm, so logAuthEvent is never called.
  2. Admin-API user creationsupabase.auth.admin.createUser() bypasses the form path entirely. Used by tests, scripts, and any future admin tooling.
  3. Race window — even on the email/password path, logAuthEvent runs as the freshly-authenticated session, so it can race with token establishment on slow networks.

Net effect: signups_this_month is a lower bound, not a count.

Plan

Trigger-based, single source of truth:

  1. Extend the existing create_user_profile() function in the monolithic migration to also INSERT INTO auth_audit_logs (user_id, event_type, success, event_data) with event_type = 'sign_up'. The function already runs AFTER INSERT ON auth.users for every signup path (form, OAuth, admin API).
  2. Decide whether to keep the application-level logAuthEvent calls in SignUpForm.tsx. Likely remove them to avoid double-writes — the trigger now owns this event.
  3. Re-evaluate the test that prompted this work (tests/rls/service-role.test.ts "service role can read all audit logs"). Once the trigger lands, restoring ≥2 makes sense (one from each createTestUser call in beforeAll).
  4. Audit the other event_type values queried by get_security_metrics() (sign_in, sign_in_success, sign_in_failed) for similar gaps. sign_in doesn't have an auth.users INSERT to hook — that one stays in application code.

Reference

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinggap-auditIdentified during 2026-04-25 planned-vs-shipped auditpriority:p2Medium — schedule (feature gaps, partial implementations)

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions