HTTP APIs

larsggu.meReference › audit event

audit event

{id, occurred_at, actor, action, target, context, outcome}

An append-only record of who did what to which object and when, written for later reconstruction rather than for debugging.

Description

An audit log and an application log look similar and serve opposite purposes. The application log is written for the engineer reading it this afternoon and may be sampled, reformatted or dropped. The audit log is written for somebody reconstructing a sequence months afterwards, possibly under obligation, and it is therefore append-only, complete, and stable in shape.

Seven fields carry almost everything worth asking. An identifier for the event, the instant it occurred, the actor, the action, the target object, the surrounding context, and the outcome. The actor field has to distinguish a person from an application acting for a person from an application acting for itself, because those three are different answers to the question the log exists to answer.

Failures belong in the log as much as successes. A refused attempt is ordinarily more interesting than a permitted one, and a log containing only what succeeded cannot show that anything was tried. Records are written after the operation resolves, so the outcome is known and no entry describes work that did not happen.

The log is also a place where sensitive values accumulate by accident. Recording that a field changed, with the identity of the field, is enough; recording the value it changed from and to reproduces the data inside a store with different retention and different access rules from the one it came out of.

Fields

Fields of audit event
FieldFormMeaning
idopaque identifierUnique per event. Lets a record be referred to unambiguously.
occurred_atRFC 3339 instantWhen the action resolved, in UTC, with the offset written out.
actorstructuredType, identifier and, where relevant, the principal being acted for.
actiondotted stringWhat was attempted, from a fixed vocabulary rather than free text.
targetstructuredThe object type and identifier the action addressed.
contextstructuredRequest identifier, address, and the credential used.
outcomeallowed or deniedIncluding the reason on refusal.

Example

A refused attempt

{"id":"aud_9f14",
 "occurred_at":"2026-09-06T09:41:07Z",
 "actor":{"type":"application","id":"app_19","on_behalf_of":"usr_82"},
 "action":"invoice.export",
 "target":{"type":"invoice","id":"in_3390"},
 "context":{"request_id":"req_5c2","credential":"at_..."},
 "outcome":{"result":"denied","reason":"scope_missing"}}

The refusal is recorded with its reason; nothing about the invoice contents is copied into the entry.

Failure modes

  • Logging only successful actions, which cannot answer what was attempted.
  • Collapsing person, application and application-acting-for-person into one actor field.
  • Copying changed values into the entry, which duplicates sensitive data under different retention rules.
  • Permitting updates or deletions of entries, which removes the only property that makes the log worth keeping.

Topic: Data shape. Last modified 2026-09-06.