authz-casbin
Authorizes requests with an embedded Casbin enforcer. The model and policy are loaded once at config load — from files on the gateway host or from inline strings — and every request is evaluated locally with no network calls. Place it after authentication (so a consumer identity is available) and before the upstream node.
For each request the plugin builds a Casbin request tuple (subject, object, action):
- subject — the authenticated consumer (
consumer.nameincontext.message) if present, else the value of a configured header, else"anonymous". - object — the request path.
- action — the request method.
enforce((subject, object, action)) decides the outcome.
Configuration
One of the two source pairs is required.
| Key | Type | Default | Description |
|---|---|---|---|
model_path | string | — | Path to a Casbin model file on the gateway host. Requires policy_path. |
policy_path | string | — | Path to a Casbin policy (CSV) file on the gateway host. Requires model_path. |
model | string | — | Inline Casbin model config text. Requires policy. |
policy | string | — | Inline Casbin policy (CSV) text. Requires model. |
username_header | string | x-user | Header the subject is read from when no consumer identity is attached; compared case-insensitively. |
# inline model + policy
- id: authz
type: authz-casbin
config:
username_header: x-user
model: |
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
policy: |
p, admin, /data, GET
g, alice, admin
# model + policy files on the gateway host
- id: authz
type: authz-casbin
config:
model_path: /etc/featherbit/model.conf
policy_path: /etc/featherbit/policy.csv
username_header: x-user
Behavior
The enforcer is compiled eagerly at config load; a malformed model or policy fails fast (config is rejected) rather than at request time.
On success the context passes through the success port unchanged. On a denied decision the plugin exits through the dedicated denied port:
context.response.status_code=403- Body:
{"message":"Access Denied"}withcontent-type: application/json
An enforcer evaluation error (not expected with a valid model) is treated the same as an explicit denial and also exits on denied; the model/policy is compiled eagerly at load, so this should never occur at request time in practice. There is no separate infra-failure path — authz-casbin evaluates entirely in-process and never calls out over the network, so the error port is declared but unused.
Behavior notes
- Subject resolution. The subject is resolved in order: the attached consumer identity (
consumer.name) when present, then the header named byusername_header(defaultx-user), then"anonymous"— integrating with featherbit's consumer model. - Per-node model/policy. There is no global plugin-metadata layer; supply the model/policy per node via the file paths or inline strings.
- Enforcer construction. Casbin's enforcer is async to build; featherbit constructs it at load on a dedicated short-lived thread with its own Tokio runtime, then shares it read-only (
Arc<Enforcer>) across requests.
Ports
authz-casbin declares three output ports: success, denied (a 403 rejection is prepared — the enforcer denied the request), and error (declared for consistency with the rest of the auth family, but never produced). denied is a mandatory port, same as success: the policy compiler rejects any policy that leaves it unwired.
edges:
- from: authz-casbin.success
to: upstream.in
- from: authz-casbin.denied
to: client.in
Errors
This node never fails at execution time: it always returns through success, so its error port is never taken.