Skip to content

Auth Audit Events

Every significant auth action emits an audit event. Events flow from the auth service through a durable PGMQ queue to the control-plane consumer, which writes them to the project’s audit log and fans them out to any configured webhooks. The transport is at-least-once and survives an auth-service restart.

The 15 event types

EventWhen it fires
login.successA password sign-in succeeded (a Better Auth session was created).
login.failureA password sign-in failed (bad credentials). Carries the attempted email + IP/UA.
logoutA user signed out (POST /logout).
signupA new user was created.
password.reset.requestedA password-reset email was requested (POST /recover).
password.reset.completedA recovery-flow code was exchanged for a session (reset finished).
password.changedAn authenticated user set a new password (PUT /user).
email.verifiedAn email was confirmed (OTP or link).
session.createdA session was created via an OAuth/PKCE code exchange.
session.revokedA user’s sessions were revoked (on sign-out).
oauth.callbackAn OAuth sign-in completed at the callback.
token.refreshedA refresh-token grant minted a new access token.
mfa.enabledA TOTP factor was verified for the first time.
mfa.verifiedA TOTP code was verified.
mfa.disabledA TOTP factor was unenrolled.

Event shape

Each event carries the project id, the event type, and (where applicable) the user id, email, IP address, user agent, an error code (failures), and a small metadata object (e.g. session_id).

Where they go

  • Audit log — query via the management API: GET /api/v1/admin/audit (and …/audit/export).
  • Webhooks — configure a project webhook subscribed to auth events; the consumer dispatches each event as an HTTP delivery. See the webhooks docs.

Notes

  • login.failure is emitted once, by the auth service. The control-plane per-IP brute-force limiter only rate-limits credential endpoints; it does not emit its own auth event, so there is no double-counting.
  • password.reset.requested is recorded whether or not the email exists, but the HTTP response is always 200 (the audit log is operator-private; the wire response never leaks user existence).

Next: Auth Overview.