Audit log
Field-level reference for audit events, the action catalog, and the query API.
The audit log records control-plane actions in a namespace: who did what to firewalls, tokens, teams, webhooks, and Trusted Builders, and what was denied. For review workflows, see Review the audit log.
Event shape
{
"id": "01J...",
"createdAt": "2026-07-03T10:22:41Z",
"namespace": "ns-01KYA296JWEE36NDNRTJ4KM82Q",
"action": "firewall.rule.upsert",
"resourceType": "firewall",
"resourceId": "3e7f5cb806f26e3beae2",
"actorUserId": "user-7d2f...",
"actorTokenIdentifier": "5f8a...",
"requestId": "8f4c2e...",
"interactionId": "build-4711",
"remoteAddr": "203.0.113.7",
"userAgent": "bsfw/1.4.0",
"requestMethod": "PUT",
"requestPath": "/v1/ns-01KYA296JWEE36NDNRTJ4KM82Q/config/3e7f5cb806f26e3beae2/rules/delay-14d",
"outcome": "success",
"statusCode": 200,
"eventData": { "rule": "delay-14d" }
}Fields
| Field | Type | Description |
|---|---|---|
id | string | Event ID |
createdAt | string | When the action happened |
namespace | string | Namespace ID the action targeted |
action | string | What was done, see catalog below |
resourceType | string | firewall, token, namespace, session, team, trusted_builder, license_set, webhook |
resourceId | string | The specific resource. For firewalls this is the firewall ID, never the display name; firewalls created in the dashboard get a generated ID that differs from their name, so search by ID |
actorUserId | string | Acting user's ID, when the session belongs to one. An opaque identifier (the token's OIDC subject), not an email or display name; the dashboard resolves it to a name where it can |
actorTokenIdentifier | string | Hash-derived identifier of the acting token. Never contains token material, but is stable, so repeated use of one token is correlatable |
requestId | string | Request ID, shared with firewall log entries from the same request |
interactionId | string | Interaction ID from the token suffix, if any |
remoteAddr, userAgent, requestMethod, requestPath | string | Request metadata. Path excludes the query string |
outcome | string | success or failure |
statusCode | number | HTTP status returned |
errorMessage | string | Short failure reason, on failures |
eventData | object | Action-specific detail, for example the missing permission on a denial or the claim mismatch on an OIDC failure |
Action catalog
| Action | Emitted when |
|---|---|
auth.failed | A request presented a missing or invalid token and its requested namespace could be assigned safely to one tenant |
auth.namespace_denied, authz.namespace_denied | A valid token was used outside its namespace or without namespace access |
authz.denied | An action was attempted without the required permission; eventData.permission names it |
firewall.access | Firewall traffic access was denied per-resource |
firewall.config.upsert, firewall.config.delete, firewall.config.rollback | Configuration imported/changed, firewall deleted, config rolled back |
firewall.rule.upsert, firewall.rule.delete | A rule changed or was removed |
firewall.exception.upsert, firewall.exception.delete | An exception changed or was removed. See exceptions on inherited rules when the rule came from a parent firewall |
firewall.credentials.upsert | Upstream credentials were set or rotated |
license_set.create, license_set.update, license_set.delete | License set management |
namespace.provision, namespace.create, namespace.update, namespace.delete, namespace.clone | Namespace lifecycle; provision is the auto-provisioning on an admin's first login |
token.personal.create, token.service.create, token.delete | Token lifecycle |
team.create, team.update, team.delete, team.member.add, team.member.remove | Team management |
trusted_builder.create, trusted_builder.update, trusted_builder.delete | Trusted Builder management |
webhook.create, webhook.update, webhook.delete, webhook.test, webhook.secret.rotate, webhook.unquarantine | Webhook management. Subscribable as audit.webhook.* webhook events |
oidc.exchange | A Trusted Builder exchange succeeded, or a failed exchange identified a configured builder. Malformed tokens and unknown audiences are not visible in a tenant audit log |
Exceptions on inherited rules
Firewalls can inherit rules from an ancestor. A team can add an exception on its own firewall for one of those inherited rules.
Successful events stay attached to the team's firewall because that is where the configuration changed. They also record which firewall owns the rule.
In the dashboard, open an event and look under Event data. In the API response, the same object is named eventData. These fields identify the rule owner:
rule_source_firewall_idis the ID of the firewall that owns the rule referenced by one saved exception.exception_rule_source_firewall_idsis the list of rule-owner firewall IDs involved in a config import or rollback. It can include the changed firewall when an exception references one of its local rules.
Audit filters do not search Event data. To find successful exceptions against a baseline, filter by the relevant action, open the results, and compare these fields with the baseline firewall ID. Filtering by the baseline's resourceId finds source-permission denials filed against that baseline, not successful changes filed against child firewalls.
| What happened | What you will find |
|---|---|
| A team saved an exception on an inherited rule | A firewall.exception.upsert event on the team's firewall. Under Event data, rule_source_firewall_id identifies the firewall that owns the rule |
| A team imported a config or rolled one back, changing exceptions | A firewall.config.upsert or firewall.config.rollback event on the team's firewall. Under Event data, exception_rule_source_firewall_ids lists the distinct rule owners involved |
| Someone lacked permission on the rule's source firewall | An authz.denied event filed against the source firewall. Under Event data, target_firewall identifies the firewall they were changing and rule_id identifies the rule |
Adding an exception to an inherited rule requires permission on both the firewall being changed and the source firewall that owns the rule. The denial event shows which of those checks failed.
Query API
GET /v1/<namespace-id>/audit| Parameter | Description |
|---|---|
action | Exact action string from the catalog |
resourceType | Resource type |
resourceId | Specific resource |
actorUserId | Acting user's raw ID, not the display name. Copy it from the event detail in the dashboard |
outcome | success or failure |
from, to | RFC 3339 time bounds |
limit | Page size, default 100, maximum 1000 |
offset | Page offset |
The response wraps events with total, limit, and offset for paging.
The CLI exposes the same filters with bsfw audit. See the CLI reference.
Related
- How-to: Review the audit log
- Concept: Observability, Access and permissions
- Reference: CLI, API, Logs
API
The management API under /v1/<namespace-id>. Endpoints for configuration, rules, exceptions, logs, metrics, observations, audit, webhooks, tokens, teams, and Trusted Builders.
CLI
Install and configure bsfw. Commands, profiles, authentication, flags, environment variables, output formats, and exit codes.