Expand description
Request authorization (DW-020, feature analysis sections 4.7 and 4.15).
Authorization answers “is this caller ALLOWED here?” after
authentication (DW-019) has answered “who is this caller?”. One
route’s rules live in crate::config::Authz; this module
evaluates them against the request’s identity, consumer groups, and
EFFECTIVE client IP.
§Semantics (frozen)
- 403 vs 401: a DENIED authenticated (or anonymous-but-
IP-gated) request answers 403 “forbidden”; an anonymous request on
a route whose authorization carries identity rules answers 401
(authentication is implied by identity rules). The one
anonymous-permitting case is an
ip_acl-ONLYAuthz— IP allow can grant anonymous access (documented exception; an operator writingip_acland nothing else wants an IP gate, not a login wall).auth_requiredon the route still independently forces authentication regardless of authorization. - Within one Authz, deny wins:
denied_consumers/denied_groupsbeatallowed_*at the same level; in the IP ACL the deny list is checked before the allow list. - IP ACL against the EFFECTIVE client IP: the
X-Forwarded-For-resolved client when the direct peer is insidegateway.trusted_proxies(the DW-009 chain — seeeffective_client_ip), otherwise the direct peer. A spoofed XFF from an untrusted peer never influences the decision. - Scopes: every
required_scopesentry must appear in the JWTscopeclaim, which may be a space-separated string ("read write") or an array of strings (flattened byauthnto the space-separated form). API-key/Basic identities carry no claims and never satisfy scope rules. - Claims:
required_claimsis exact string equality on the stringified claim value; a listed claim absent from the token fails the match. Only string- and number-valued claims are captured on the identity (authndrops bool/null/object claims), so such a claim can never satisfy arequired_claimsentry. ALL comparisons — consumers, groups, scopes, claims — are case-sensitive.
§Precedence chain (done-when of DW-020)
Rules attach at five levels with the frozen gateway precedence
consumer > route > service > listener > global. authorize
resolves the chain through AuthzChain:
- A deny at ANY level wins — a consumer-level deny beats a route-level allow, and vice versa. Denials are absolute.
- Otherwise the most specific level with rules governs: its own
evaluation is the verdict (allow or deny under its rules), and
less-specific levels are not consulted. A level without an
Authz(or with an empty one) is transparent.
Live links (#123): every level has a config attachment —
consumers[].authorization (applies once authentication identifies
the consumer), routes[].authorization, services[].authorization,
listeners[].authorization (the accepting listener), and the
gateway-level authorization (global). Authorization runs on
requests that resolved a route, per the documented request-path
order; unrouted 404s never reach the chain.
Dry run (DW-041): any attachment may set dry_run: true — its
denials are then evaluated, logged, and counted by the caller
instead of enforced. The resolver (resolve) walks PAST a dry
deny and stops only at a live one, so a live deny at ANY level still
enforces: monitor mode observes what a block would reject without
ever making enforcement more permissive.
§Failure posture
Authorization failures are logged server-side only (via the
decision’s reason when warranted); clients receive a generic 403
body with no rule detail (which list matched, which claim was absent
— none of it is their business).
Structs§
- Authz
Chain - The five authorization levels in frozen precedence order (most
specific first). Levels without an
Authzattachment today passNone; the chain structure is the DW-020 done-when — links activate as their config fields land. - Authz
Context - Everything one authorization evaluation needs to know about the request.
- Resolved
- One resolved chain evaluation (DW-041): the enforcement verdict plus,
when a
dry_runattachment would have denied, the observation the caller logs and counts instead of enforcing.
Enums§
- Authz
Level - Which chain level produced an authorization decision (DW-041): the
proxy needs the denying link’s own config (its
dry_runflag) to decide whether a deny is enforced or only observed. - Decision
- The outcome of an authorization decision.
Functions§
- authorize
- Resolve the precedence chain. Merge semantics (documented, frozen):
- effective_
client_ ip - Resolve the EFFECTIVE client IP (DW-009 trusted-proxy chain).
- evaluate_
one - Evaluate ONE
Authzblock.Nonemeans the block imposes nothing (no rules at all — a transparent level);Some(Allow)/Some(Deny)is this level’s verdict. - resolve
authorizewith the dry-run observation attached (DW-041): the enforced verdict plus the would-have-denied attachment for the caller to log and count. SeeResolvedfor why a dry deny never masks a live one.