Require User Claims Policy
Authorize requests by validating claims on the authenticated user against a
configurable rule — allowlists (in), exact values (eq), and prefixes
(startsWith), combined with and/or.
Run this policy after any authentication policy (for example Open ID JWT Auth or one of its provider-specific variants): the authentication policy proves who the caller is, and this policy decides what they may call — for example, pinning a route to specific service accounts, OAuth clients, tenants, or groups without writing custom code.
Configuration
The configuration shows how to configure the policy in the 'policies.json' document.
Code
Policy Configuration
name<string>- The name of your policy instance. This is used as a reference in your routes.policyType<string>- The identifier of the policy. This is used by the Zuplo UI. Value should berequire-user-claims-inbound.handler.export<string>- The name of the exported type. Value should beRequireUserClaimsInboundPolicy.handler.module<string>- The module containing the policy. Value should be$import(@zuplo/runtime).handler.options<object>- The options for this policy. See Policy Options below.
Policy Options
The options for this policy are specified below. All properties are optional unless specifically marked as required.
rule(required)<undefined>- The authorization rule evaluated against the authenticated user's claims (request.user.data, populated by the authentication policy that runs before this one — a JWT policy, API key auth, mTLS, etc.). A rule is either a single claim check (eq, in, or startsWith) or an and/or combination of nested rules. Combinators may nest up to three levels deep. Requests that fail the rule receive a 403 Forbidden response.
Using the Policy
Overview
The require-user-claims-inbound policy authorizes requests by evaluating a
rule against the claims of the authenticated user (request.user). It
separates authentication from authorization: an authentication policy — a JWT
policy such as open-id-jwt-auth-inbound, API key auth, mTLS, or any other —
proves who the caller is; this policy then decides what they may call.
Typical uses:
- Pin a route to specific caller identities — service accounts, OAuth clients,
or workload identities — by allowlisting the
suband/oremailclaims. - Require an exact value on any claim, including nested claims (for example an
AWS STS token's
lambda_source_function_arnunder thehttps://sts.amazonaws.com/namespace). - Match prefixes with
startsWith, for example AWS assumed-role subjects likearn:aws:sts::123456789012:assumed-role/my-role/<session>where the session name varies. - Require membership in a group or role carried in an array-valued claim.
Configuration
Code
This policy must run after an authentication policy that populates
request.user. If no authenticated user is present on the request, the policy
returns 401 Unauthorized. If the rule evaluates to false, it returns
403 Forbidden.
Rules
A rule is either a single claim check or an and/or combination of nested
rules (and/or may nest up to three levels deep; a claim check may appear at
any level):
{ "and": [rule, ...] }— every nested rule must pass.{ "or": [rule, ...] }— at least one nested rule must pass.{ "claim": <claim>, "eq": value }— the claim equals the value.{ "claim": <claim>, "in": [value, ...] }— the claim equals any listed value.{ "claim": <claim>, "startsWith": "prefix" }— the claim is a string starting with the prefix.
Each claim check uses exactly one operator. To combine operators on the same
claim, use and/or with one check per operator.
Selecting claims
Claims are read from the authenticated user's data (request.user.data), which
is set by whichever authentication policy ran before this one. For a JWT auth
policy this is the full decoded token payload; for API key auth it is the key's
metadata.
claim is a light JSON-path selector:
- Dot notation addresses top-level and nested claims —
email,address.country. - Bracket notation with quotes addresses claim names that contain dots or
slashes (namespaced claims), which dot notation cannot express —
['https://example.com/roles'], or nested:['https://sts.amazonaws.com/']['lambda_source_function_arn']. Single or double quotes both work; single quotes avoid backslash-escaping when the selector is written in a JSONpolicies.json. The two notations may be mixed, e.g.realm_access['some.key']. subfalls back torequest.user.subwhen the user data has nosubproperty, so subject checks also work with authentication policies that only set the subject (for example API key authentication).
Evaluation semantics
Every check fails closed:
- A missing claim never matches.
- Object-valued claims never match.
- Comparisons are strict and type-sensitive: the string
"42"does not equal the number42. Note that Google-issued tokens carrysubas a string of digits, and$env(...)substitution always produces strings — quote numeric values accordingly. startsWithonly matches string claim values, and an empty prefix is rejected as a configuration error.- When a claim value is an array (for example
groupsorroles), a check passes if any element satisfies the operator.
Denied responses never echo claim values or expected values. The failing claim
checks and the caller's sub are written to the request log instead.
Related policies
- Open ID JWT Auth —
verifies token signature, issuer, and audience, and populates
request.user. - JWT Scope Validation —
requires that the space-delimited
scopeclaim contains all configured scopes; use it for OAuth scope enforcement.
Read more about how policies work