Expand description
AuthzPolicy capability trait. See plan/ecosystem/02-capabilities.md §AuthzPolicy.
An AuthzPolicyPlugin answers “given this request context, is the
action allowed?” using an externalised policy language — Cedar, CEL,
OPA/Rego, or a custom engine. It sits one layer above
crate::auth::AuthPlugin: auth establishes who the caller is,
authz-policy decides what they may do with that identity.
§Why the return shape is an enum, not Result<_, String>
This is the one capability in bext-plugin-api where a flat enum is
load-bearing. Callers branch on three genuinely distinct outcomes:
- Allow. Let the request proceed untouched.
- Deny. Short-circuit with a 403, forwarding the reason to the
logs and (optionally) to the client. The reason string is policy
author–controlled (“principal lacks
posts:writeonposts/123”) and the host must not discard it. - Mutate. Let the request proceed, but rewrite the response
on the way out — inject headers (CSP,
X-Tenant, audit trailers) or substitute the body (redact fields, stamp a watermark). Cedar’s response-side obligations and a handful of custom engines need this; without it the trait cannot represent what they do.
Folding these into Result<_, String> would collapse Mutate into
Allow, which silently drops the rewrite. Folding Deny into Err would
conflate “the policy said no” with “the policy engine crashed” — the
host treats those completely differently (Deny is a normal 403, engine
failure is a 500 and a wakeup).
Backend-failure errors still exist, but they live on the outer
AuthzPolicyPlugin::evaluate signature’s companion methods
(AuthzPolicyPlugin::reload_policies) and in the contract documented
on evaluate itself (engines fail-closed: on internal error, return
PolicyDecision::Deny with the error as the reason). This keeps the
evaluate hot path allocation-free in the success cases — no
Result::unwrap_or_else chains at every call site.
§Backends
Two reference backends ship alongside this trait in crates/bext-impls/:
bext-policy-cedar— AWS Cedar. Rich entity/resource model, designed around exactly the Allow / Deny / obligations shape.bext-policy-cel— Google’s Common Expression Language. Simpler boolean expressions over a flat attribute map; maps to Allow/Deny with Mutate unused.
An OPA/Rego backend is planned but not shipped as a reference — deploying a Rego runtime is heavier than the ref-plugin bar.
§AuthzPolicy vs Auth, in one paragraph
crate::auth::AuthPlugin turns a bearer token or session cookie
into an crate::auth::AuthUser (id, scopes, attributes). It knows
nothing about what the user is trying to do — it cannot, because it
runs before routing. AuthzPolicyPlugin runs after routing has
identified the action and resource, and evaluates the per-request
policy against the already-authenticated principal. A site can run
with only Auth (scope strings are enough), only AuthzPolicy (every
request is anonymous but policy-gated), or both stacked (auth fills
principal, policy evaluates action).
Modules§
- fuel
- Fuel budgets for WASM authz-policy plugin calls. Matches the convention
in
crate::locking::fuelandcrate::scheduled::fuel.
Structs§
- Policy
Context - Evaluation context for a single authorization decision.
Enums§
- Policy
Decision - Outcome of a single policy evaluation.
Traits§
- Authz
Policy Plugin - A policy engine plugin.