Skip to content

Reference

alter audit

Read the audit log: runtime calls, portal actions, grant events, and traces.

Every credential-touching call and every admin action produces an audit row. These read-only commands query the log from several angles.

alter audit list [--since ...] [--start ...] [--end ...] [--action ...] [--policy-decision ...] [--root-grantee ...]
alter audit providers [--app ...]
alter audit show <trace-id>
alter audit explain <trace-id>
alter audit portal-actions [--start ...] [--end ...] [--principal-kind ...] [--resource-type ...]
alter audit grant-events [--start ...] [--end ...] [--grant-type ...] [--provider ...]
alter audit traces [--start ...] [--end ...] [--actor ...]
alter audit threads [--start ...] [--end ...] [--app ...] [--actor ...]
alter audit thread <thread-id>
alter audit agents [--start ...] [--end ...] [--app ...]
alter audit agent <actor-id> [--principal-kind actor|agent|key] [--additional-key-ids ...]
alter audit integrity-check --start ... --end ... [--table ...]

All commands need dashboard_audit:read and accept --output. For line-oriented pipelines, use --output jsonl with jq / grep. That is also the CLI’s export path — alter audit list --since 30d --output jsonl > audit.ndjson is the programmatic equivalent of the dashboard’s CSV/NDJSON export. Enum, ID, and date filters are validated client-side, so a typo fails fast; free-form filters (--action, --provider, --resource-type) pass through and simply match nothing when misspelled.

alter audit explain <trace-id> is the diagnostic companion to show: instead of raw events, it translates the trace’s terminal state into a concrete fix — a policy denial names the policy posture to review (alter policy show-app); a scope mismatch names the rotate command; a suspended agent points at alter agents resume (suspension is reversible — re-consent and rotation do not help); a revoked agent points at recreating it (alter agents create — revocation is terminal); a revoked/expired grant points at re-consent or secret rotation; an unexplained provider 4xx points at the request-shape lint in alter verify (a provider 401/403 points at re-consent or credential rotation instead, and a 429 at backoff — do not run verify for those); a provider 5xx says retry with backoff. The mapping is deterministic over fields the audit rows already carry — when nothing matches, it says so and defers to show.

explain accepts json, jsonl, or table. Its report is a single object, so jsonl falls back to pretty-printed JSON.

Time filters: --start <iso> / --end <iso> give absolute bounds on every list-style command. The --since <duration> shorthand (e.g. 1h, 7d) — a relative start — is only available on audit list; the other list-style commands accept --start / --end only. On audit list, --start and --since are mutually exclusive.

Audit rows across the trail — token retrievals, outbound API calls, approvals, grant and delegation lifecycle, portal and Wallet policy changes, and provisioning.

FlagDefaultDescription
--since <duration>—Relative start, e.g. 24h, 7d. Mutually exclusive with --start.
--start <iso> / --end <iso>—Absolute bounds.
--app <app-id-or-name>allFilter by app.
--action <action>alle.g. token.retrieved.
--actor <actor-id>allFilter by actor.
--provider <provider>allFilter by provider ID (e.g. google), not display name.
--policy-decision <decision>allALLOW, DENY, or ERROR (case-sensitive).
--root-grantee <id>allFilter by root grantee: the ID of the end user, group or agent the access was originally granted to, which is the id field of alter end-users list, alter managed-secrets groups list or alter agents list. A malformed ID exits 2 before any request. A backend that did not apply the filter exits 1 with no rows. See Search by root grantee.
--limit <n>100Page size (1–500).
--offset <n>0Pagination offset.
Terminal window
alter audit list --since 24h --policy-decision DENY

--root-grantee <id> narrows the list to access originally granted to one end user, group or agent. Take the ID from the id field of alter end-users list --output json for an end user, alter managed-secrets groups list --output json for a group, or alter agents list --output json for an agent. The filter composes with every other list filter and with --limit / --offset.

Terminal window
alter audit list --since 7d --root-grantee 3f6c2a1e-8b9d-4c7e-a5f0-1d2e3f4a5b6c --output json

When the backend applies the filter, its response carries a root_grantee_coverage field. The CLI prints that value and what it means to stderr, so a script can tell the result is partial. stdout carries the rows only, in every --output format. Today the value is direct_access_only, and the CLI prints:

No audit record carries a root grantee yet, so this result has only token and managed-secret records of the user’s, group’s or agent’s direct use of its own grant: retrievals, refreshes made during a request, failures, and refusals of a request to use the grant once it was identified. Access through a delegation, background (refresh-ahead) refreshes, provider calls, grant lifecycle events, approvals and attempts refused before the grant was identified are not included.

A delegated row names the delegate, not the original grantee, which is why access through a delegation is not found. Existing rows are never filled in later, so an empty result does not mean the access was never used. Rows that never carry a grantee (portal and Wallet configuration changes, and IDP provisioning) are left out while the filter is set. A root_grantee_coverage value this CLI version does not recognize still marks the result as partial. The CLI prints the raw value with a generic notice.

A response without a root_grantee_coverage value comes from a backend that predates the filter. That backend ignores --root-grantee and returns the unfiltered trail. The CLI then prints no rows, says on stderr that --root-grantee was not applied, and exits 1.

The table’s RULE column names the policy rule a row is about: the rule that decided a policy decision (a deny, an IP-allowlist rejection, a step-up or approval requirement, or the rule whose obligations shaped a permit), or the policy rule a portal or Wallet change created, updated, or deleted. In JSON output the same ids are policy.policy_rule_id (the policy_rule_id field of the policy object) and resource_id. End-user policy changes made in the Wallet appear with log_type end_user_config, actor: null and the end user who made the change in end_user — for example:

Terminal window
alter audit list --since 7d --action policy_rule.created --output json \
| jq '.[] | {log_type, resource_id, actor: (.end_user.identifier // .actor.identifier // .developer_id)}'

In --output json, each row’s action_type is read, write, denied or error: denied marks a request Alter refused before the provider was called (a policy, scope, approval, key or rate-limit refusal of a credential request, or an outbound API call it cannot send as written), and error is everything else that did not succeed, server faults included.

Every list-style audit command emits the rows themselves in every output format — --output json is the rows array, matching every other list command. When more rows remain, the command prints the next --offset to run on stderr, so a | jq pipeline keeps clean data on stdout.

The provider IDs present in an app’s audit events — the values --provider accepts. One vocabulary across categories: OAuth provider IDs (google), managed-secret template IDs (openai) — a custom managed secret is identified by its name-derived slug — and identity-provider types (okta). Derived from the audit data itself (the same source as the dashboard’s Provider filter dropdown), so a provider whose configuration was since deleted still appears as long as its audit rows do.

FlagDefaultDescription
--app <app-id-or-name>ALTER_APP_ID / workspace pinApp whose audit trail to facet.
Terminal window
alter audit providers --app my-app
alter audit providers --output json | jq -r '.[].provider_id'

Show every event for one trace, by trace ID.

Terminal window
alter audit show <trace-id>

Admin actions taken in the dashboard or via the CLI — app CRUD, key mints, policy edits. The default table includes TYPE (read, write, or error) and RESULT (success, failure, denied, or error). When a record omits the classification, TYPE displays —; additive future string values are shown verbatim instead of aborting the listing. Successful list/export/integrity operations remain visible as reads; their summary payload is not reported as a created resource. Failed or denied dashboard actions have type error, regardless of the intended operation (denied applies to credential requests and API calls Alter refused; see list).

FlagDescription
--principal-kind <kind>portal, sdk, system, or pat. Use pat to see CLI-driven actions.
--resource-type <type>Filter by resource type.
--action <action>e.g. app.created.
--app, --start, --end, --limit, --offsetAs above (--limit range 1–500, default 100).
Terminal window
# BSD/macOS date:
alter audit portal-actions --principal-kind pat \
--start $(date -u -v-7d +%Y-%m-%dT%H:%M:%SZ)
# GNU date (Linux): --start $(date -u -d "7 days ago" +%Y-%m-%dT%H:%M:%SZ)

Grant-lifecycle events for both OAuth and managed-secret grants.

FlagDescription
--grant-type <type>oauth or managed_secret.
--provider <provider>Filter by provider ID (e.g. google), not display name.
--app, --start, --end, --limit, --offsetAs above (--limit range 1–500, default 100).
Terminal window
# BSD/macOS date:
alter audit grant-events --grant-type oauth \
--start $(date -u -v-30d +%Y-%m-%dT%H:%M:%SZ)
# GNU date (Linux): --start $(date -u -d "30 days ago" +%Y-%m-%dT%H:%M:%SZ)

Trace summaries — one row per request trace, with event count and status.

FlagDescription
--actor <actor-id>Filter by actor.
--app, --start, --end, --limit, --offsetAs above (--limit range 1–200, default 50).
Terminal window
# BSD/macOS date:
alter audit traces --app <app-id-or-name> \
--start $(date -u -v-24H +%Y-%m-%dT%H:%M:%SZ)
# GNU date (Linux): --start $(date -u -d "24 hours ago" +%Y-%m-%dT%H:%M:%SZ)

Conversation threads — groups of related traces. One row per thread, with trace and event counts.

FlagDescription
--actor <actor-id>Filter by actor.
--app, --start, --end, --limit, --offsetAs above (--limit default 50, max 200).
Terminal window
alter audit threads --app <app-id-or-name>

Show every trace and event for one thread, by thread ID.

Terminal window
alter audit thread <thread-id>

Audit activity grouped by principal — one row per agent-identity key group, actor, or effective agent, with thread / trace / event counts. Key groups (principal_kind: "key") are the primary kind: keys sharing one agent identity merge into a single row whose keys facets carry the per-key IDs and counts (key_count is the group’s true distinct-key total).

FlagDescription
--app, --start, --end, --limit, --offsetAs above (--limit default 50, max 200).
Terminal window
alter audit agents --app <app-id-or-name>

Show one principal’s audit detail (its threads and traces), by ID.

FlagDescription
--principal-kind <kind>actor (default), agent, or key — whether <actor-id> is an actor ID, an effective-agent ID, or an API-key ID (the primary agent identity in the grouped view).
--additional-key-ids <ids...>Sibling API-key IDs of a multi-key agent group (repeat the option or space-separate IDs; at most 50). Requires --principal-kind key; merges every key’s events into one timeline.
--app <app-id-or-name>Filter by app.
Terminal window
alter audit agent <actor-id> --principal-kind agent
# Merge a multi-key agent group's timeline (ids from `alter audit agents` → keys facets):
alter audit agent <key-id> --principal-kind key --additional-key-ids <key-id-2> <key-id-3>

Verify audit-log integrity over a date window. Read-only: the server recomputes each row’s content hash and, on credential rows that carry one, its lineage hash, and reports any row where either no longer matches (tampering), mutating nothing. Each entry of invalid_rows names the row’s table and id and, in failed_hash, which hash failed: content, lineage or both. Between them the two hashes cover how a credential row’s access was authorized: the grantee, the access path and delegation chain, the verified end-user subject where one was recorded, and the root grantee, except references to records that can be deleted (an end user, an agent, an API key), which are cleared when that record is. The end user’s display identifier and name are recorded but not hash-covered. Rows written before the lineage hash was introduced carry none and are checked by content hash alone. The window must be 90 days or less.

FlagRequiredDescription
--start <iso>yesStart of the window (inclusive).
--end <iso>yesEnd of the window (exclusive). Window must be ≤ 90 days.
--table <name>noLimit to one audit table (default: all): api-calls, oauth-tokens, or managed-secrets.
Terminal window
# BSD/macOS date:
alter audit integrity-check \
--start $(date -u -v-7d +%Y-%m-%dT%H:%M:%SZ) \
--end $(date -u +%Y-%m-%dT%H:%M:%SZ)
# GNU date (Linux): --start $(date -u -d "7 days ago" +%Y-%m-%dT%H:%M:%SZ)

Investigate denied calls

Terminal window
# Recent denials
alter audit list --since 24h --policy-decision DENY
# Find a trace to expand (trace IDs come from `audit traces`), then drill in
# (BSD/macOS date; GNU: --start $(date -u -d "24 hours ago" +%Y-%m-%dT%H:%M:%SZ))
alter audit traces --start $(date -u -v-24H +%Y-%m-%dT%H:%M:%SZ) \
--output json | jq -r '.[].trace_id'
alter audit show <trace-id>

Stream a day of activity into a pipeline

Terminal window
alter audit list --since 24h --output jsonl | jq -c 'select(.action == "token.retrieved")'

Find CLI / PAT-driven admin actions

Terminal window
# BSD/macOS date:
alter audit portal-actions --principal-kind pat \
--start $(date -u -v-7d +%Y-%m-%dT%H:%M:%SZ)
# GNU date (Linux): --start $(date -u -d "7 days ago" +%Y-%m-%dT%H:%M:%SZ)

Report an issue with this page

Necessary

Required for sign-in, security, authorization, and remembering your choices.

Always active

Analytics

Helps us understand which product and documentation features are useful.

Performance diagnostics

Uses performance tracing and privacy-masked session replay to diagnose problems.

You can change these choices at any time from Cookie settings.