What it does
theauth.explain(agentId, action, resource, options?) mirrors theauth.authorize() and returns the reasoning instead of just the verdict. It answers questions like “which rule let this through?”, “which delegation carried it?” and “why was this denied?”.
It only reads. It writes no audit rows, does not increment rate limit counters, does not spend approvals, and never caches.
Result. A denial is a successful explanation (decision: "deny"). A database failure returns EXPLAIN_LOAD_FAILED, and empty input returns EXPLAIN_INVALID_INPUT.
Result
Near misses
When no grant matches,matchedGrant is absent and nearMisses lists up to three grants that almost allowed the call, best first. Own grants and delegated grants are both considered. A grant that matched on resource and action but failed a constraint is reported as matchedGrant instead, so nearMisses stays empty then.
Near misses are computed from the same permission lists, with no extra queries and no side effects. To turn explain into CI checks, see policy testing.
Semantics
explain() follows authorize(): the first matching rule wins, own permissions are tried before delegated ones, and when both deny the own verdict stands. When a delegated rule matched but failed a constraint, matchedGrant and constraints show that rule and reason says so, even though the code stays the one authorize() returns.
A rule with requireApproval reports decision: "escalate" and code approval_required. Explain cannot spend an approval.
The unified policy.evaluate() engine (deny overrides, risk, taint) is not explained yet. The engine option is reserved for it and only accepts "authorize".
Options
Hooks
Hooks can call external services, soexplain() skips beforeAuthorize unless you pass runHooks: true. When skipped, hook.configured is true and hook.evaluated is false, which tells you the live answer may differ.
With runHooks: true the hook runs through the same timeout and fail-closed handling as authorize(). It receives dryRun: true, so a hook that writes records or notifies someone should check that flag and stay quiet. A deny, escalate, timeout or error from the hook is reflected in decision, code and hook.
Related
- Permission simulator for what-if overrides, matrices and access reviews
- Hooks for
beforeAuthorizeanddryRun