> For the complete documentation index, see [llms.txt](https://docs.fortifiedid.se/audit/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.fortifiedid.se/audit/readme.md).

# Audit

## Introduction

The Audit module receives audit events from internal clients (LdapClient, EntraID, JdbcClient) and persists them to a configurable storage backend. It provides a tamper-evident record of all data changes performed by users via pipes.

Audit events are published to an internal event bus address. The module subscribes to this address and writes each event through the configured writer. Failed writes are logged as warnings but do not fail the originating operation.

## Configuration

{% hint style="info" %}
**Module name:** `AuditModule`
{% endhint %}

{% tabs %}
{% tab title="Properties" %}

<table><thead><tr><th>Name</th><th>Description</th><th>Default</th><th data-type="checkbox">Mandatory</th></tr></thead><tbody><tr><td><code>writer</code></td><td>Storage backend. One of: <code>jsonlines</code>, <code>stdout</code>, <code>logger</code></td><td><code>jsonlines</code></td><td>false</td></tr><tr><td><code>path</code></td><td>File path for JSON Lines output. Required when <code>writer</code> is <code>jsonlines</code>.</td><td></td><td>true</td></tr></tbody></table>
{% endtab %}

{% tab title="Example" %}

```json
{
  "name": "AuditModule",
  "config": {
    "writer": "jsonlines",
    "path": "/var/log/fortified/audit.jsonl"
  }
}
```

{% endtab %}
{% endtabs %}

### Writers

| Writer      | Description                                                                            |
| ----------- | -------------------------------------------------------------------------------------- |
| `jsonlines` | Appends one JSON event per line to the configured file path. Default.                  |
| `stdout`    | Writes JSON events to standard output. Useful for container environments.              |
| `logger`    | Writes events through the platform logger at INFO level under the `AUDIT` logger name. |

{% hint style="warning" %}
**Logger writer: log4j2 configuration required**

The `logger` writer logs at INFO level under the named logger `AUDIT`. The default `log4j2.xml` shipped with the server does not include an entry for this logger, so events fall through to the Root logger (level `WARN`) and are silently suppressed.

Add the following entry to `config/log4j2.xml` to enable output:

```xml
<AsyncLogger name="AUDIT" level="INFO"/>
```

This is especially important in Docker-based deployments where audit visibility relies on container log output.
{% endhint %}

## Log format

Events are stored as JSON Lines — one JSON object per line. Each event includes:

| Field            | Type     | Description                                                        |
| ---------------- | -------- | ------------------------------------------------------------------ |
| `timestamp`      | ISO-8601 | When the operation occurred                                        |
| `correlation_id` | string   | Trace ID from the originating request                              |
| `operation`      | string   | One of: `CREATE`, `READ`, `UPDATE`, `DELETE`, `SEARCH`             |
| `client_type`    | string   | Client that performed the operation (e.g. `ldap`, `entra`, `jdbc`) |
| `data_source`    | string   | Target data source name                                            |
| `entity_type`    | string   | Type of object affected                                            |
| `entity_id`      | string   | Identifier of the affected object                                  |
| `subject`        | string   | Identity of the acting principal                                   |
| `attributes`     | object   | Additional principal attributes (e.g. role, tenant)                |
| `pipe`           | string   | Name of the pipe that initiated the operation                      |
| `changes`        | array    | List of changed attributes (for UPDATE operations)                 |

### Example event

```json
{"timestamp":"2026-04-14T10:23:01.452Z","correlation_id":"a1b2c3","operation":"UPDATE","client_type":"ldap","data_source":"default","entity_type":"inetOrgPerson","entity_id":"uid=alice,ou=users,dc=example,dc=com","subject":"admin@example.com","attributes":{"role":"operator"},"pipe":"update-user","changes":[{"attribute":"mail","old":"alice@old.example.com","new":"alice@example.com"}]}
```

## Per-client audit configuration

Each client module that supports audit logging accepts an `audit` block in its configuration. All flags default to `false`.

{% tabs %}
{% tab title="LdapClient" %}

```json
"audit": {
  "create": true,
  "update": true,
  "delete": true
}
```

{% endtab %}

{% tab title="EntraID" %}

```json
"audit": {
  "create": true,
  "update": true,
  "delete": true
}
```

{% endtab %}

{% tab title="JdbcClient" %}

```json
"audit": {
  "create": true,
  "update": true,
  "delete": true,
  "read": true
}
```

{% endtab %}
{% endtabs %}

## AuditContext

Callers pass an `AuditContext` alongside operations to supply principal identity and correlation context.

| Field        | Description                                                                          |
| ------------ | ------------------------------------------------------------------------------------ |
| `traceId`    | Correlation ID, reused from the existing `trace_id` concept                          |
| `subject`    | Identity of the acting principal (e.g. `user@example.com`). Defaults to `anonymous`. |
| `attributes` | Additional principal attributes (e.g. role, tenant)                                  |

The platform resolves `AuditContext` in this priority order:

1. Explicit `AuditContext` passed by the caller
2. Context derived from the current session
3. Default: `anonymous` principal with the current trace ID


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.fortifiedid.se/audit/readme.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
