Audit logs that actually help

Logging everything is logging nothing. Pick the events that matter, structure them properly, and make them searchable.

· LoginWith team

Audit logs are one of those features everyone agrees are important and most teams implement badly. The two common failures: logging too much (so nobody can find anything) or logging too little (so you can’t answer the question when it matters).

What a useful audit log answers

A good audit log answers one question: who did what, when, to what, from where?

  • Who: subject — user ID, service ID, or API key ID
  • What: action — user.login, permission.granted, post.deleted
  • When: timestamp — UTC, millisecond precision
  • To what: object — the entity acted upon (user ID, post ID, workspace ID)
  • From where: context — IP, user agent, session ID, request ID

If every log entry has all five, you can answer nearly any investigative question. If even one is missing, you have a gap you’ll regret.

What to log

The must-haves for any SaaS:

  • Authentication events: login, logout, login failure, MFA success/failure, password reset, email change
  • Session events: session created, session terminated (by user or admin)
  • Permission changes: role grants and revokes, permission edits, workspace membership changes
  • Destructive actions: deletes of anything the user couldn’t recover in 30 seconds
  • Admin actions: impersonation, bulk updates, API key creation

What to skip:

  • Read events unless you’re in healthcare or finance. Logging every page view drowns the signal.
  • Internal system events that aren’t user-attributable. Those go in app logs, not audit logs.

Structure

JSON. Every field above. One entry per event. Don’t combine events (“user logged in and changed email”) into a single row — make them two rows with a correlation ID.

{
  "timestamp": "2026-04-20T14:32:11.421Z",
  "subject": {"type": "user", "id": "usr_abc123"},
  "tenant_id": "tenant_xyz",
  "action": "user.email_changed",
  "object": {"type": "user", "id": "usr_abc123"},
  "context": {
    "ip": "1.2.3.4",
    "user_agent": "Mozilla/5.0...",
    "session_id": "sess_def456",
    "request_id": "req_ghi789"
  },
  "metadata": {
    "old_email": "jane@old.com",
    "new_email": "jane@new.com"
  }
}

Storage

Audit logs are append-only and high-volume. Store them separately from your main database:

  • A dedicated Postgres schema with write-only access from your main app, or
  • An object store (S3) with date-partitioned files, or
  • A log analytics system (Datadog, Splunk, Honeycomb)

Retention: 1 year minimum for most SaaS, 7 years for regulated industries. Check your compliance framework.

Make them queryable

Logs nobody can query are compliance theater. Admins and support reps need a UI:

  • Filter by subject, action, time range
  • Full-text search on metadata
  • Export to CSV for investigations

This is not optional. You’ll be glad you built it the first time a customer asks “who changed our workspace name last Tuesday?”

Want auth that just works?

Get started with LoginWith