Security Audit Events Are Versioned Product Contracts
Build investigation-ready event schemas with explicit outcomes, durable delivery decisions, and privacy boundaries.
A log line that says “request completed” is useful for troubleshooting, but weak evidence for an investigation. Responders need to reconstruct who attempted which action, against what resource, under which decision, and whether the effect actually happened.
I would treat a security audit event as a versioned interface between product engineering and detection engineering. That interface deserves compatibility rules and failure tests just as much as an API does.
Distinguish decisions from effects
Here is an illustrative event for a completed role assignment:
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"schema_version": 1,
"event_id": "evt-0197",
"event_type": "role_assignment.completed",
"tenant_id": "tenant-example",
"actor_id": "user-example",
"target_id": "membership-example",
"action": "grant_billing_admin",
"decision_id": "decision-042",
"policy_version": "roles-12",
"outcome": "success",
"occurred_at": "2026-09-11T23:30:00Z"
}
Production identifiers need appropriate uniqueness and validation; the values above are placeholders. A prior authorization event should have a different event type. An allow decision followed by a database failure is not a completed role assignment.
Include both occurrence and ingestion time in the pipeline so analysts can reason about delayed delivery. Preserve an event identity across retries and make consumers tolerant of duplicates. A correlation identifier helps join events but must not be treated as authentication evidence when a caller can supply it.
Choose the durability boundary
For a database-backed privileged mutation, a transactional outbox can commit the mutation and audit intent together. A dispatcher then delivers the event with retries. This prevents a successful mutation from losing its audit intent because the logging service is temporarily unavailable.
It does not guarantee prompt delivery. Monitor the oldest undelivered event, queue growth, and failed dispatches. If the database cannot durably record the intent, decide whether the privileged operation must fail. Lower-risk diagnostic logging can have a different availability policy.
OWASP’s logging guidance covers event selection, sensitive-data exclusions, and protection of log data. I would use that baseline while defining a narrower schema for each consequential business action.
Review privacy and investigation utility together
Do not put bearer tokens, passwords, or full request bodies into the audit event. Stable opaque identifiers usually support investigation with less exposure. Authorized investigators can retrieve additional context through controlled systems instead of making the logging platform a second unrestricted data store.
The schema owner should publish examples and a compatibility policy. Adding an optional field may be safe; changing the meaning of success is not. Detection owners need fixture events before a producer deploys a semantic change.
My release exercise would execute a successful grant, a denied grant, and a failed mutation while the dispatcher is offline. After recovery, an analyst should reconstruct all three accurately. The measure of success is an answerable investigation, not a high volume of JSON.