Audit log examples: what a SaaS audit log should record

What is an audit log, and what should yours record? SaaS audit log examples: event categories, required fields, sample JSON, retention and integrity.

An audit log is a chronological record of security-relevant events: who did what, to which resource, when, from where, and whether it worked. NIST’s glossary (opens in a new tab) puts it more briefly: “a record providing documentary evidence of specific events.” In a SaaS app, it’s how you, and often your customers, answer “who changed this?” months later. The audit log examples below show what that looks like in practice.

This guide covers the events worth recording, the fields every entry needs, sample JSON entries, and how to keep the log trustworthy.

What is an audit log?

An audit log is a structured, append-only record of consequential actions, kept for accountability and investigation. It’s a specific kind of log. NIST SP 800-92 (opens in a new tab) describes logs in general as records of events in an organization’s systems, used for troubleshooting, performance, recording user actions and investigating malicious activity.

The difference is purpose. An audit log is written to be evidence, so it’s designed differently from the logs engineers read while debugging.

Audit logApplication logProduct analytics
Question it answersWho did what, and did it work?What went wrong in the code?How do people use the product?
Main readersSecurity, compliance, customer adminsEngineersProduct teams
SchemaStable, versionedFree-form or semi-structuredEvent-specific
RetentionDefined period per categoryShortVaries
Can it be edited?NoUsually rotated or overwrittenOften sampled or transformed

What type of events does an audit log generally record?

An audit log generally records authentication, permission changes, sensitive data access and exports, administrative and security settings changes, billing changes and staff access. These are the events someone will ask about after an incident or a dispute.

Two primary sources line up on this. NIST SP 800-53 control AU-2 (opens in a new tab) lists event types such as password changes, failed logons, security attribute changes and administrative privilege usage. OWASP’s Logging Cheat Sheet (opens in a new tab) says to always log authentication successes and failures, authorization failures, user administration actions, access to sensitive data, data import and export, and use of break-glass accounts.

For a multi-tenant SaaS app, that translates into these categories:

CategoryExample event names
Authenticationuser.login.succeeded, user.login.failed, mfa.disabled, password.reset.completed
Members and permissionsmember.invited, member.role.changed, member.removed, sso.connection.updated
Keys and integrationsapi_key.created, api_key.revoked, webhook.endpoint.created, integration.connected
Data access and exportreport.exported, records.bulk_downloaded, document.viewed (for sensitive documents only)
Settings and securitysettings.retention.changed, ip_allowlist.updated, audit_log.exported
Billingsubscription.plan.changed, payment_method.updated, invoice.refunded
Staff and support accesssupport_access.approved, support_session.started, support_session.ended
Data lifecycleworkspace.deleted, user.data.erased

Don’t log every page view or click. OWASP warns that a blind checklist approach can create “alarm fog” that hides real problems. Pick events that are consequential, and review the list as the product changes. AU-2 asks for that review too.

What fields should every audit log entry have?

Every entry needs to say what happened, when, where, who did it, to what, and with what outcome. NIST SP 800-53 control AU-3 (opens in a new tab) lists the event type, time, location, source, outcome and the identity of any individuals or objects involved. OWASP frames the same idea (opens in a new tab) as “when, where, who and what”, plus an interaction identifier that links related events.

FieldWhy it’s thereExample
idDeduplicate and reference one eventevt_7Hq2
actionWhat happened, from a fixed listmember.role.changed
occurred_atWhen, in UTC ISO 8601YYYY-MM-DDThh:mm:ssZ
actorWho did it: a user, API key, service or staff member{ "type": "user", "id": "usr_41" }
org_idWhich tenant it belongs toorg_acme
targetWhat it was done to{ "type": "member", "id": "usr_88" }
outcomesuccess, failure or denied, plus a reason codedenied / insufficient_role
sourceWhere from: IP, user agent, client{ "ip": "203.0.113.7" }
request_idLinks events from one request or jobreq_5c1
changesBefore and after for configuration changes{ "role": ["member", "admin"] }
schema_versionLets the format evolve2

Use stable IDs rather than names, since names change. Emit the event from the server, after the change commits, not from a frontend success message.

Audit log examples: sample JSON entries

These audit log examples use the fields above. They’re an example schema for your own application, not a standard, and all values are fictional. Timestamps are shown as a format placeholder.

A failed sign-in. The actor isn’t authenticated yet, so record that rather than trusting the submitted identity.

{
  "id": "evt_01",
  "action": "user.login.failed",
  "occurred_at": "YYYY-MM-DDThh:mm:ssZ",
  "actor": { "type": "anonymous" },
  "org_id": "org_acme",
  "target": { "type": "user", "id": "usr_41" },
  "outcome": "failure",
  "reason": "invalid_credentials",
  "source": { "ip": "203.0.113.7", "user_agent": "Mozilla/5.0" },
  "request_id": "req_9a1"
}

A role change. Configuration changes carry before and after values.

{
  "id": "evt_02",
  "action": "member.role.changed",
  "occurred_at": "YYYY-MM-DDThh:mm:ssZ",
  "actor": { "type": "user", "id": "usr_12" },
  "org_id": "org_acme",
  "target": { "type": "member", "id": "usr_88" },
  "changes": { "role": ["member", "admin"] },
  "outcome": "success",
  "request_id": "req_9a2"
}

A data export. Record what was exported and how much, never the exported data.

{
  "id": "evt_03",
  "action": "report.exported",
  "occurred_at": "YYYY-MM-DDThh:mm:ssZ",
  "actor": { "type": "user", "id": "usr_12" },
  "org_id": "org_acme",
  "target": { "type": "report", "id": "rpt_invoices" },
  "details": { "format": "csv", "row_count": 1840 },
  "outcome": "success",
  "request_id": "req_9a3"
}

An API key created by an integration. Record the key’s ID or prefix, never the key.

{
  "id": "evt_04",
  "action": "api_key.created",
  "occurred_at": "YYYY-MM-DDThh:mm:ssZ",
  "actor": { "type": "api_key", "id": "key_admin_3f" },
  "org_id": "org_acme",
  "target": { "type": "api_key", "id": "key_9d2", "prefix": "sk_9d2" },
  "outcome": "success",
  "request_id": "req_9a4"
}

Should customers see your audit log?

For B2B SaaS, usually yes, for events in their own organization. Customer admins use a customer-facing audit log to answer their own questions without opening a ticket. GitHub’s organization audit log (opens in a new tab), for example, shows organization owners the events that affected their organization in the last 180 days. Slack’s Audit Logs API (opens in a new tab), available on its Enterprise plans, describes every event as an actor, an action, an entity and a context.

You’ll still need an internal log. Keep the two separate:

Customer-facing audit logInternal audit log
ScopeOne customer organizationAll tenants and the platform
IncludesMembers’ actions, API keys, settings, exportsPlus security signals, system events and staff activity
DetailReadable action names, limited internal reasonsFull reason codes and investigation context
AccessCustomer owners and adminsSecurity and a small set of engineers
DeliveryDashboard view, export or APIYour log pipeline or security tooling

Decide deliberately whether staff access to a customer’s data appears in that customer’s log. Microsoft, for instance, logs every Lockbox access request (opens in a new tab) and action, and makes them accessible through the Office 365 Management Activity API.

How should you log support and impersonation actions?

When staff act inside a customer’s account, record two identities: the staff actor who performed the action and the customer subject whose account was used. Add a reference to the support session so you can link each action to the approval behind it. The impersonation audit log guide covers the schema and how to reconcile access records with application events.

If you use Devora, it records the access side: requests, decisions, reasons, scope, timing, self-approval, revocation and termination events. It doesn’t see the business actions inside your app, so those audit events are yours to emit.

How long should you keep audit logs, and how do you protect them?

Keep audit logs for a defined period per category, then delete them on schedule. NIST’s AU-11 asks organizations to retain audit records for a period they set, to support after-the-fact investigations and meet regulatory and organizational requirements. OWASP adds the other half: logs mustn’t be destroyed before the retention period ends, or kept beyond it.

There’s no universal number. Set retention from your legal and contractual obligations, and publish the customer-facing period. As one reference point, Devora keeps request and session metadata (opens in a new tab) for 180 days after a session ends and its pseudonymous security audit for 365 days.

Protect integrity and confidentiality:

  • Restrict writes. NIST’s AU-9 asks you to protect audit information from unauthorized access, modification and deletion, and to alert when it happens. Give your application role insert-only access to the audit table.
  • Detect tampering. OWASP recommends tamper detection, copying logs to read-only storage quickly, and recording all access to the logs. A hash chain or write-once storage in a separate account both work.
  • Keep secrets and personal data out. OWASP lists session IDs, access tokens, passwords, payment data and sensitive personal data as things to remove, mask, hash or encrypt rather than log directly.
  • Don’t lose events. Write audit events in the same transaction as the change, or through a durable outbox, so a failure can’t silently drop them.

How do you check that your audit log works?

Run each scenario in staging and inspect the stored events. These are pass conditions to check, not results we’ve run.

ScenarioPass condition
Sign in with a wrong passwordOne failure event, with no password or token in it
Change a member’s roleOne event with the actor, target, and before and after roles
A request is rejected for lack of permissionA denied event, and no success event
Export a reportEvent records format and size, not the data
The audit store is unavailable during a changeThe change fails, or the event is retried durably; it is never silently lost
The application tries to update an existing audit rowThe database refuses
A customer admin opens their audit logOnly their organization’s events appear
An event passes its retention periodIt’s deleted on schedule

Start with the categories table and the field list, emit events from the server, and test the failure cases before the happy path. If support access to customer accounts is part of your audit story, create a Devora account and try one staging session, then line its access record up with your own audit events.

Sources

Quick answers

Common questions, answered clearly.

Direct answers to the questions teams usually ask when evaluating this approach.

What is an audit log?

An audit log is a chronological record of security-relevant events in a system: who did what, to which resource, when, from where, and whether it succeeded. It exists for accountability and investigation, so it is structured, kept for a defined period and protected from being changed.

What type of events does an audit log generally record?

Authentication events such as sign-ins and MFA changes, permission and membership changes, API key and integration changes, data exports and sensitive reads, administrative and security settings changes, billing changes, and staff or support access to customer accounts. Routine page views usually belong in analytics instead.

What is the difference between an audit log and an application log?

Application logs help engineers debug and operate the system, and they are often verbose and short-lived. An audit log records consequential actions for accountability, uses a stable schema, is retained for a defined period and is protected against modification and deletion.

How long should you keep audit logs?

Long enough to investigate incidents and meet your legal, regulatory and contractual obligations, and no longer. There isn't one universal number. Write down a retention period per event category, enforce it automatically, and tell customers how long their own audit log is available.

Should customers be able to see the audit log?

For B2B SaaS, usually yes, for events in their own organization. Customer admins use it to answer who changed a setting or exported data. Keep an internal log too, for security signals and system events that customers shouldn't see.

Does Devora provide an audit log for my application?

No. Devora records the access side of support sessions: requests, approval decisions, reasons, scope, timing, self-approval, revocation and termination. Business actions inside your application, such as a role change or an export, need audit events emitted by your own code.

Put it into practice

Give your team context.Keep control of access.

Bring approvals, scoped sessions, and access history into your support workflow.