acl
Group-based access control. Restricts which already-authenticated consumers may reach a route, keyed on the consumer's group. It does not authenticate — an upstream auth node (e.g. key-auth) must have attached the consumer identity first, writing consumer.name and (optionally) consumer.group into context.message. Place it after auth and before the upstream node.
Configuration
At least one of allowed_by or denied_by is required.
| Key | Type | Default | Description |
|---|---|---|---|
allowed_by | array of strings | — | Consumer groups permitted through. When non-empty, a consumer whose group is not listed (including one with no group) is rejected. |
denied_by | array of strings | — | Consumer groups blocked. Checked before allowed_by — deny wins. |
rejected_code | integer | 403 | HTTP status for list rejections. |
rejected_msg | string | — | Custom rejection message; overrides the default. |
type: acl
config:
allowed_by: ["partners", "internal"]
denied_by: ["banned"]
rejected_code: 403
Behavior
Checks run in order:
- No consumer attached — if
consumer.nameis absent fromcontext.message, the request is rejected with status401and messageMissing authentication.. - Deny list first — if the consumer's group is in
denied_by, the request is rejected (deny wins even when the same group is also inallowed_by). - Allow list — if
allowed_byis non-empty and the consumer's group is not listed, the request is rejected. A consumer with no group is rejected wheneverallowed_byis set.
Every rejection writes a JSON body ({"message": ...} with content-type: application/json) onto context.response, sets the status, and exits through the denied port. Admitted requests pass through the success port unchanged.
Matching is by consumer group only. featherbit models a consumer's membership as a single consumer.group, so this plugin implements the classic group-allowlist form with allowed_by / denied_by lists of group names; arbitrary consumer labels and external-user JWT claims are not matched.
Ports
acl declares three output ports: success, denied (a rejection is prepared), and error (never actually used — the plugin never fails). Like success, denied is a mandatory port: the policy compiler rejects any policy that leaves it unwired. Wire acl.denied straight to client so the prepared 401/403 reaches the caller instead of continuing into upstream:
edges:
- from: acl.success
to: upstream.in
- from: acl.denied
to: client.in
Errors
This node never fails at execution time: it always returns through success, so its error port is never taken.