Do these 3 things before closing this tab:
1Repair Windows errors before they cause bigger problems2Fix the driver behind crashes, sound loss and screen glitches3Clear out junk files and repair common Windows errorsIn agentgateway, “fail open” and “fail closed” describe two unrelated events. The first is a CEL expression that cannot be evaluated, for example because a JWT claim is missing. The second is an external authorization service that is down or returning errors. Mixing them up can leave a mandatory check unenforced.
The short version: in standalone HTTP authorization, an expression that errors is treated as false. A require that is false or errors denies the request. A deny that is false or errors simply does not match, so it blocks nothing by itself. External authorization availability is a separate setting, failureMode, which defaults to FailClosed.
As an Amazon Associate I earn from qualifying purchases.
Scope note: this article is based on the official agentgateway documentation, which is published under rolling “latest” paths. Those pages do not name a specific release, and no geographic limitation is stated. Check the behavior against the version and configuration mode you actually run. The docs label their authorization code examples as automatically tested; that is the vendor’s statement, not something verified independently here.
Gotcha 1: a failing CEL expression is just false
The standalone HTTP authorization documentation states: “A CEL expression that cannot be evaluated is treated as false.” Its example of an undefined value is a missing jwt.aud. Whether “false” is safe depends on which rule type holds the expression.
#1 Best Overall
| Rule type | Expression true | Expression false or errors | Net effect |
|---|---|---|---|
require |
Condition satisfied | Request denied | Fails closed |
deny |
Request blocked | Rule does not match; it does not deny | Effectively fails open for that rule |
allow |
Request permitted | Rule does not match; fallback applies | Depends on whether other allow rules exist |
The trap with deny
Take the docs’ rule deny: 'jwt.aud != "my-service"'. It reads like “block anything not meant for my service.” But if the token has no aud claim, the expression errors, is treated as false, and the deny does not match. The request is not blocked by that rule. If other rules permit it, or nothing else gates it, traffic proceeds.
The fix: use require for mandatory conditions
The docs say: “For mandatory conditions such as ‘all requests must have a valid audience claim,’ prefer require, which fails closed.” Every require rule must match, so a missing claim denies the request instead of slipping past.
When a claim is optional and you are testing it, guard it with has(), as the docs do: has(jwt.group) && jwt.group == 'eng'. This evaluates cleanly to false when the claim is absent, rather than relying on an error being coerced to false.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Scan for outdated or missing drivers - takes under a minuteDriver Scan →How standalone rules combine
The documented evaluation order for standalone HTTP authorization:
- No rules configured: the request is allowed.
- Any matching
denyblocks the request. - Any non-matching
requireblocks the request. - A matching
allowpermits it. - Otherwise the fallback depends on whether any allow rule exists. With allow rules configured, unmatched requests are denied (allowlist behavior). With none, unmatched requests are allowed (denylist behavior).
This is why an erroring deny is risky in a denylist setup: with no allow rules, nothing else catches the request. In an allowlist setup, a failed deny is less dangerous only because the request must still match some allow rule.
Kubernetes AgentgatewayPolicy works differently
On Kubernetes, authorization lives in an AgentgatewayPolicy authorization block with one action and a policy made of CEL match expressions. The syntax and combination rules differ from the standalone rules examples, so don’t copy semantics between them.
Rank #4
- Allow: grants access when at least one expression matches.
- Require: every expression must evaluate true.
- Deny: blocks when at least one expression matches.
Across policies, Deny is evaluated first, then Require, then Allow. If any Allow rule exists, one Allow expression must match. If only Require rules exist, requests that pass all of them can proceed.
The Kubernetes guide’s treatment of erroring expressions is not covered in the material reviewed here; the “treated as false” sentence appears on the standalone page. The same reasoning is still prudent: write mandatory conditions as Require, and guard optional claims with has().
Best Value
- Used Book in Good Condition
Authentication comes first
A missing, malformed, or unverifiable JWT fails authentication with a 401 before any authorization expression runs. Authorization denials return 403. So the missing-claim problem applies to a token that is valid but lacks a particular claim, not to a missing or invalid token.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Gotcha 2: external authorization has its own failure mode
If you delegate decisions to an external authorization service, the API reference provides failureMode:
FailClosed(default): the request is denied if the service is unavailable or returns an error.FailOpen: the request continues in that situation.
This is about service availability. It has nothing to do with a CEL deny evaluating to false. Setting FailClosed won’t make an errored deny expression block traffic, and a require rule’s strictness doesn’t tell you what happens when your auth service is down.
The Tool Desk
Outbyte PC Repair FREEClear out junk files and repair common Windows errorsFree Scan →Outbyte Driver Updater FREEScan for outdated or missing drivers - takes under a minuteDriver Scan →Quick comparison
| Axis | CEL expression error | External auth service failure |
|---|---|---|
| Failure source | Expression cannot be evaluated (e.g., missing jwt.aud) |
Service unavailable or returning an error |
| Controlled by | Rule type: require, deny, allow |
failureMode |
| Default behavior | Treated as false; outcome depends on rule type | FailClosed |
| Risky choice | Mandatory check written as deny |
FailOpen on a security-critical path |
Neighboring failure settings
Other features have their own switches, which is another reason to avoid a global mental model of “fail open”:
- External processing (ExtProc):
failOpenapplies only before request body bytes begin streaming to the processor. Once streaming starts, a failure returns an error even withfailOpen. - Remote rate limiting: fails closed by default on service failure, with an explicit
failOpenoption to allow requests while the rate limit service is unavailable.
Review checklist
- Identify your mode: standalone HTTP authorization rules, or Kubernetes AgentgatewayPolicy actions.
- Express every must-have condition as
require(Require), not as an inverteddeny. - Guard optional claims with
has()before comparing them. - Know your fallback: are any allow rules configured? If not, unmatched requests are allowed in standalone mode.
- Test with tokens that are valid but missing the claim, not just tokens with wrong values. The standalone docs point to the built-in CEL playground in the agentgateway UI for trying expressions.
- Set
failureModedeliberately for external authorization, and leave it atFailClosedunless availability outweighs enforcement.
The Kubernetes setup path requires installing agentgateway, creating a Gateway and a sample backend, then applying an AgentgatewayPolicy. The documentation reviewed contains no statistics or benchmarks on these behaviors, and none are cited here.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




