This content is dedicated to our next version. It is work in progress: its content will evolve until the new version is released.

Before that time, it cannot be considered as official.

Audit Log

Bonita writes one JSON event per login, failed login and logout to a dedicated audit log, so that a SIEM can collect who authenticated, when and from where.

What is recorded

Bonita writes an event for each:

  • login: successful or failed, including the login attempts rejected because the account is locked out by the brute-force login protection;

  • logout.

All the login paths of the Bonita web application are covered: the login page and the /loginservice endpoint, single sign-on (OIDC, SAML, CAS and Kerberos, Subscription editions only), and the platform administrator login. The guest user logins are not recorded.

The audit log is routed by the org.bonitasoft.runtime.audit logger, and each category of events has its own child logger: the authentication events are written at INFO level to the org.bonitasoft.runtime.audit.authentication logger. Both are on by default, in every edition and in single-node and cluster deployments alike.

Event format

Each event is a JSON object written on a single line. Its field names are modeled on the Elastic Common Schema, and fields without a value are left out. Example of a successful login (shown on several lines here):

{
  "@timestamp": "2026-10-16T09:14:41.077Z",
  "schema_version": "1",
  "event": {"category": "authentication", "action": "login", "outcome": "success"},
  "user": {"name": "walter.bates"},
  "auth": {"method": "standard"},
  "source": {"ip": "203.0.113.57"},
  "user_agent": {"original": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ..."},
  "http": {"request": {"method": "POST"}},
  "url": {"path": "/bonita/loginservice"},
  "session": {"id_hash": "8802dac666a192b6b45ed25f30f9ca0562bad8996af207e18615c4509c450863"},
  "host": {"name": "bonita-node-1"}
}
Field Description

@timestamp

Time of the event, in UTC, with milliseconds.

schema_version

Version of the event format, 1. It changes whenever the format changes.

event.category

Category of the event, authentication. A single value, not an array as in the Elastic Common Schema: it also names the logger of the event.

event.action

login or logout.

event.outcome

success or failure.

event.reason

Only set to locked_out on a login rejected by the brute-force login protection.

user.name

The logged-in user, or the username that was attempted on a failed login. A failed single sign-on login for which the identity provider returned no username has none.

auth.method

standard (username and password), oidc, saml, cas, kerberos, or platform (platform administrator). On a logout, the method of the login.

auth.provider

Only for an oidc login when several OIDC providers are configured: the provider id, as listed in the oidc.providers property (see Configure Bonita for multiple OIDC providers). On a logout, the provider of the login.

source.ip

IP address of the client, see Client IP address and User-Agent.

user_agent.original

User-Agent header of the client.

http.request.method

HTTP method of the request.

url.path

Path of the request, without query string or path parameters.

session.id_hash

SHA-256 hash of the session id, on successful logins and on logouts, to pair a logout with its login without writing the session identifier.

host.name

Name of the server that handled the request.

Where the events are written

Tomcat bundle

The events are written to <BUNDLE_HOME>/server/logs/audit.log, one event per line, and not to bonita.log. Like bonita.log, the file is rolled over every day and when it reaches 250 MB, as audit-<yyyy-MM-dd>-<n>.log.gz.

The routing is declared in server/conf/log4j2-appenders.xml:

<RollingRandomAccessFile fileName="${baseDir}/audit.log"
                         filePattern="${baseDir}/audit-%d{yyyy-MM-dd}-%i.log.gz"
                         name="Audit-File">
    <!-- The message is already a JSON event: one event per line -->
    <PatternLayout pattern="%m%n"/>
    <Policies>
        <TimeBasedTriggeringPolicy/>
        <SizeBasedTriggeringPolicy size="250 MB"/>
    </Policies>
</RollingRandomAccessFile>
...
<Logger name="org.bonitasoft.runtime.audit" level="INFO" additivity="false">
    <AppenderRef ref="Audit-File"/>
</Logger>

To also write the events with the other logs (bonita.log, and the console when enabled), remove additivity="false".

Old files are not deleted, as for bonita.log: apply the retention required by your audit policy, for example with a DefaultRolloverStrategy and a Delete action in the Audit-File appender:

<DefaultRolloverStrategy>
    <Delete basePath="${baseDir}" maxDepth="1">
        <IfFileName glob="audit-*.log.gz"/>
        <IfLastModified age="P365D"/>
    </Delete>
</DefaultRolloverStrategy>

Docker image

By default, the events are written on the standard output of the container, one JSON event per line with nothing around it, so that a log collector can read them as JSON. They are not repeated with the other logs.

As for the access logs, two environment variables switch the outputs on or off: AUDIT_LOG_STDOUT_ENABLED (default true) for the standard output, and AUDIT_LOG_FILES_ENABLED (default false) for /opt/bonita/logs/audit.log. Both can be enabled at the same time, for example to keep the file for retention while a log collector reads the standard output. To write the file only, also set AUDIT_LOG_STDOUT_ENABLED=false. With the file enabled, AUDIT_LOG_APPEND_HOSTNAME adds a folder named after the host to its path, so that the nodes of a cluster sharing the logs folder do not write the same file.

Old files are not deleted either: add the Delete action of the retention example to the Audit-File appender of a log4j2-appenders.xml mounted on /opt/bonita/conf/logs. With AUDIT_LOG_APPEND_HOSTNAME=true, the files are one folder deeper: use maxDepth="2" and glob="/audit-.log.gz".

Customized logging configuration

A log4j2-appenders.xml customized before Bonita 2027.1 does not declare the audit logger and its appenders: the events are then written with the other logs, in the format of the other logs, and the AUDIT_LOG_* environment variables have no effect in the Docker image. Add the appenders and the org.bonitasoft.runtime.audit logger of the default file to it, for the Tomcat bundle as for a file mounted on /opt/bonita/conf/logs in the Docker image.

Switch the audit log off

Set the level of the org.bonitasoft.runtime.audit logger to OFF in log4j2-appenders.xml, for example in the Tomcat bundle:

<Logger name="org.bonitasoft.runtime.audit" level="OFF" additivity="false">
    <AppenderRef ref="Audit-File"/>
</Logger>

To leave out the authentication events only, add their logger with the OFF level instead:

<Logger name="org.bonitasoft.runtime.audit.authentication" level="OFF"/>

Log4j2 reloads the file automatically, without restart. In the Docker image, you can also set AUDIT_LOG_STDOUT_ENABLED=false, with AUDIT_LOG_FILES_ENABLED not set or false, when creating the container. These variables do not change the level of the org.bonitasoft.runtime.audit.authentication logger in a mounted log4j2-appenders.xml.

Client IP address and User-Agent

source.ip is the address of the client as seen by Tomcat, and user_agent.original its User-Agent header. Bonita does not read the X-Forwarded-For header itself: behind a reverse proxy or a load balancer, source.ip is the address of the proxy unless Tomcat’s RemoteIpValve is configured in server/conf/server.xml. Set its internalProxies attribute to match your proxies only: a client that reaches Bonita without going through them could otherwise choose the IP address written in the audit log. In the Docker image, REMOTE_IP_VALVE_ENABLED=true enables the valve with Tomcat’s default trusted proxies (private and loopback address ranges).

When the Bonita UI Builder backend calls Bonita on behalf of a user, it sends the IP address and the User-Agent of the user’s browser in the X-Bonita-Client-Ip and X-Bonita-Client-User-Agent headers. These headers are ignored unless the following property is set to true, in bonita-platform-community-custom.properties (or with its environment variable):

Property Default Description Environment variable

bonita.runtime.security.audit.trust.client.headers

false

Uses the X-Bonita-Client-Ip header, when it is an IP address, as source.ip, and the X-Bonita-Client-User-Agent header as user_agent.original.

BONITA_RUNTIME_SECURITY_AUDIT_TRUST_CLIENT_HEADERS

Only set it to true when browsers cannot reach Bonita without going through the UI Builder proxy, which removes these headers from their requests: otherwise any client could choose the IP address written in the audit log.

Personal data and sensitive values

  • An event never contains the password, the request body, the query string or the path parameters (such as jsessionid).

  • The values coming from the request are truncated, ending with …​: username and identity provider to 256 characters, User-Agent to 512, URL path to 1024.

  • The session id is hashed.

  • A failed login records the username that was typed.

Events that are not recorded

  • Failures at the identity provider with single sign-on: the user never reaches Bonita.

  • Session expiry. An explicit logout after the session has expired is not recorded either.

  • Bearer tokens rejected by the OIDC adapter.

  • Logins that do not go through the Bonita web application, such as calls to the Java LoginAPI from code running in the server.

  • Login requests without any username: they are anonymous, not failed logins.