Audit logging is available in Onyx v4.3 and later,
on self-hosted deployments where you control the log pipeline.
Overview
Onyx emits a normalized, structured audit-event stream for security-relevant actions — authentication, user and access-control changes, admin configuration changes, and credential access. Every event is a single JSON object, so you can forward the stream to any SIEM — Splunk, Microsoft Sentinel, Elastic, Google Chronicle, AWS Security Lake — with no Onyx-side integration to build. You point your log shipper at Onyx’s logs, filter the audit stream, and parse the JSON. Field names and the action taxonomy are shaped toward OCSF (the Open Cybersecurity Schema Framework), so events map cleanly onto the event classes most SIEMs already understand. This maps directly onto common compliance controls — SOC 2 CC7 and the NIST 800-53 / FedRAMP AU family (AU-2 auditable events, AU-3 record content, AU-6 review, AU-12 generation).What gets captured
Authentication
Authentication
Login success, login failure, logout, registration, password forgot, password reset, and email verification.
User & access management
User & access management
User creation (admin invites), deletion, deactivation, reactivation, role changes,
and user-group membership changes.
Configuration & resources
Configuration & resources
Create / update / delete of LLM providers, connectors, connector-credential pairs, API keys,
and credentials — plus credential-access (decrypt) events.
How it works
Audit events are emitted asINFO log records on a dedicated onyx.audit logger.
The message body of each record is a single JSON object — Onyx serializes the event itself,
so the audit line is identical regardless of your log format.
Emission is fail-safe: it never interrupts a user request or a connector run,
even if context gathering or logging fails. High-volume event classes are de-duplicated within a short (10-minute)
window using Redis. De-duplication is fail-open — if Redis is unavailable,
the dedup check is skipped and the event is still emitted,
so an audit event is never silently dropped due to infrastructure trouble (you may just see a duplicate).
The subsystem is always on — there is no enable/disable flag, output-format, or destination setting,
and the de-duplication window is fixed. The only related knob is LOG_FORMAT (below),
which shapes the surrounding log records; the audit JSON body itself is identical either way.
Event schema
| Field | Type | Description |
|---|---|---|
audit_schema_version | string | Schema version (currently "1.0"). |
ts | number | Event time, epoch seconds. |
action | string | Action taxonomy value, <domain>.<verb> (e.g. llm_provider.update). Stable, append-only. |
ocsf_class | string | authentication, account_change, or api_activity. |
outcome | string | success, failure, or denied. |
tenant_id | string | null | Tenant the action occurred in. |
actor | object | null | { user_id, email, api_key_id, auth_type }. Never contains a secret. |
resource_type | string | null | Affected resource type (e.g. llm_provider, user, api_key). |
resource_id | string | null | Affected resource identifier. |
request_id | string | null | Correlates the event with the rest of that request’s logs. |
endpoint | string | null | Route that produced the event. |
source_ip | string | null | Client IP (from X-Forwarded-For). |
extra | object | null | Additional non-secret context. |
action values are a stable, append-only contract — safe to filter and build dashboards against.
New actions may be added over time; existing ones do not change meaning.
Example event
Forward to your SIEM
Because audit events are just JSON log lines on a known logger prefix, any log shipper works.Run Onyx with JSON logging
Set
LOG_FORMAT=json so every log record is structured and carries a logger and message field.Ship Onyx's logs
Point Fluent Bit, Vector, the CloudWatch agent, Filebeat,
or your existing collector at the Onyx container stdout (or the mounted log files).
Isolate and parse the audit stream
Keep only records whose
logger starts with onyx.audit,
then parse each record’s message field as JSON to recover the event fields above.Shipper examples
Filter on the
onyx.audit prefix to capture everything.
The stream is also split into per-class child loggers — onyx.audit.authentication, onyx.audit.account_change,
onyx.audit.api_activity,
and onyx.audit.credential_access — if you want to route classes to different destinations.Event reference
Everyaction value, what triggers it, and the fields most useful for building SIEM detection rules. actor,
tenant_id, request_id, endpoint, source_ip,
and outcome are present on every event (see Event schema) and are omitted from the tables below.
Authentication
ocsf_class: authentication
action | Triggered when | Notes |
|---|---|---|
auth.login | A user successfully signs in | |
auth.login_failure | A sign-in attempt fails | outcome is failure, or denied for a non-interactive login |
auth.logout | A user signs out | |
auth.register | A new account is registered (self-signup) | |
auth.password_forgot | A password-reset email is requested | |
auth.password_reset | A password reset is completed | |
auth.email_verify | An email-verification email is requested |
User & access management
ocsf_class: account_change — resource_type is user (or user_group).
action | Triggered when | resource_id | Key extra fields |
|---|---|---|---|
user.create | An admin invites new users | — | invited_emails |
user.delete | A user is deleted | user id | target_email |
user.deactivate | A user is deactivated | user id | target_email |
user.reactivate | A user is reactivated | user id | target_email |
user.role_change | A user’s role is changed | user id | target_email, old_role, new_role |
user.group_change | A user group’s membership changes | user-group id | added_user_ids, removed_user_ids |
Configuration & resources
ocsf_class: api_activity
action | Triggered when | resource_type | resource_id | Key extra fields |
|---|---|---|---|---|
llm_provider.create / .update / .delete | An LLM provider is created, updated, or deleted | llm_provider | provider id | |
connector.create / .update / .delete | A connector is created, updated, or deleted | connector | connector id | source (on create) |
cc_pair.create / .update / .delete | A connector is linked to a credential, its status changes, or it is unlinked | cc_pair | connector-credential-pair id | connector_id, credential_id; status (on update) |
api_key.create / .regenerate / .delete | An API key is created, regenerated, or revoked | api_key | API-key id | |
credential.create / .update / .delete | A stored credential is created, updated, or deleted | credential | credential id | source (on create) |
credential.access | A stored credential is decrypted for use | — | — | Emitted on a different schema — see Credential access below |
Credential access
onyx.audit.credential_access
Credential-decrypt events predate the generalized schema and are emitted on a flat,
legacy field set for backward compatibility.
They share the onyx.audit logger tree and the same fail-safe / fail-open behavior,
but do not carry the generalized fields — there is no action, ocsf_class, outcome,
resource_type/resource_id, extra, or nested actor object, and the client IP is client_ip (not source_ip).
Parse this stream separately; detection rules written against the generalized schema will not match it.
| Field | Type | Description |
|---|---|---|
ts | number | Event time, epoch seconds. |
tenant_id | string | null | Tenant the decrypt occurred in. |
credential_type | string | Coarse category, e.g. llm_provider or connector. |
provider | string | null | Provider / source name if known (e.g. openai, google_drive). |
row_id | number | null | DB row id of the credential / LLM provider. |
user_id | string | null | Acting user id, if available (may be null for background jobs). |
auth_type | string | null | How the actor authenticated, if known. |
request_id | string | null | Correlates with the rest of that request’s logs. |
endpoint | string | null | Route that produced the event. |
client_ip | string | null | Client IP (from X-Forwarded-For). |
Notes
- Secrets are never logged. Actor objects and
extracontext are scrubbed of credential values by design. - Credential-access events (
onyx.audit.credential_access) use a separate, flat field set than the generalized schema for backward compatibility — see Credential access for the full field list. They share the same logger tree and fail-safe behavior. - For Onyx Cloud (multi-tenant) deployments, audit-log forwarding is handled differently since you don’t control the log pipeline — contact us to discuss SIEM delivery options.