Audit Logs
Track and query authentication events across your application with automatic audit logging.
Better Auth Infrastructure automatically collects audit logs for authentication events in your application. Once you've added the dash() plugin, events are tracked without any additional configuration.
How Audit Logs Are Collected
The dash() plugin hooks into your Better Auth instance and automatically records events as they happen. No manual instrumentation is needed — sign-ups, sign-ins, password changes, and more are all captured.
import { betterAuth } from "better-auth";
import { dash } from "@better-auth/infra";
export const auth = betterAuth({
plugins: [
dash(),
],
});That's it. Once dash() is active, audit logs are collected automatically.
Tracked Events
| Event | Trigger |
|---|---|
user_signed_up | New user registration |
user_profile_updated | User updates their profile |
user_profile_image_updated | User changes their avatar |
user_email_verified | Email verification completed |
user_banned | User is banned |
user_unbanned | User is unbanned |
user_deleted | User account deleted |
| Event | Trigger |
|---|---|
user_signed_in | Successful sign-in |
user_signed_out | User signs out |
session_created | New session created |
session_revoked | Single session revoked |
sessions_revoked_all | All sessions revoked |
user_impersonated | Admin starts impersonating user |
user_impersonation_stopped | Admin stops impersonating |
| Event | Trigger |
|---|---|
account_linked | Social account linked |
account_unlinked | Social account unlinked |
password_changed | Password updated |
| Event | Trigger |
|---|---|
password_reset_requested | Password reset initiated |
password_reset_completed | Password reset finished |
email_verification_sent | Verification email sent |
Tracked when using the organization plugin.
| Event | Trigger |
|---|---|
organization_created | New organization created |
organization_updated | Organization settings changed |
member_added | Member added to organization |
member_removed | Member removed from organization |
member_role_updated | Member role changed |
member_invited | Invitation sent |
invite_accepted | Invitation accepted |
invite_rejected | Invitation rejected |
invite_cancelled | Invitation cancelled |
team_created | Team created |
team_updated | Team updated |
team_deleted | Team deleted |
team_member_added | Member added to team |
team_member_removed | Member removed from team |
Tracked when using the Sentinel plugin.
| Event | Trigger |
|---|---|
security_blocked | Request was blocked |
security_allowed | Request was allowed after challenge |
security_credential_stuffing | Credential stuffing detected |
security_impossible_travel | Impossible travel detected |
security_geo_blocked | Geo-blocking triggered |
security_bot_blocked | Bot detected and blocked |
security_suspicious_ip | Suspicious IP detected |
security_velocity_exceeded | Rate limit exceeded |
security_free_trial_abuse | Free trial abuse detected |
security_compromised_password | Compromised password detected |
security_stale_account | Stale account reactivation |
Fetching Audit Logs
Client Setup
Add dashClient() to your auth client:
import { createAuthClient } from "better-auth/client";
import { dashClient } from "@better-auth/infra/client";
export const authClient = createAuthClient({
plugins: [dashClient()],
});Basic Query
const session = await authClient.getSession();
const logs = await authClient.dash.getAuditLogs({
session: session.data,
limit: 50,
offset: 0,
});
logs.data?.events; // Array of audit log events
logs.data?.total; // Total count
logs.data?.limit; // Page size
logs.data?.offset; // Current offsetQuery Parameters
| Parameter | Type | Description |
|---|---|---|
limit | number | Results per page (max 100, default 50) |
offset | number | Pagination offset (default 0) |
organizationId | string | Filter by organization |
identifier | string | Filter by identifier |
eventType | string | Filter by event type |
userId | string | Filter by user ID |
user | object | User object with ID |
session | object | Session object with user |
Filtering
// Filter by event type
const signIns = await authClient.dash.getAuditLogs({
session,
eventType: "user_signed_in",
});
// Filter by organization
const orgLogs = await authClient.dash.getAuditLogs({
session,
organizationId: "org_123",
});
// Combine filters
const orgSignIns = await authClient.dash.getAuditLogs({
session,
organizationId: "org_123",
eventType: "user_signed_in",
});Pagination
async function getAllAuditLogs(session: unknown) {
const limit = 100;
let offset = 0;
const allEvents = [];
while (true) {
const result = await authClient.dash.getAuditLogs({
session,
limit,
offset,
});
const events = result.data?.events ?? [];
allEvents.push(...events);
if (events.length < limit) break;
offset += limit;
}
return allEvents;
}