jwt-validation
Lets a request through only with a valid JWT — signed by your issuer, for your audience, not expired. Everything else gets 401.
| Phases | on_http_request |
| Terminating | No — the next action runs after it. |
| Cost | 10 Traffic Policy units per run · not on the Free plan |
Example
on_http_request:
- actions:
- type: jwt-validation
config:
issuer:
allow_list:
- value: https://example.com/issuer
audience:
allow_list:
- value: urn:example:api
http:
tokens:
- type: access_token
method: header
name: Authorization
prefix: "Bearer "
jws:
allowed_algorithms: [RS256, ES256]
keys:
sources:
additional_jkus:
- https://example.com/issuer/jwks
Start an agent endpoint with it: devgate http 8080 --traffic-policy-file policy.yaml, or paste it into a
reserved or cloud endpoint’s Traffic Policy tab in the dashboard.
Configuration
| Field | Type | Description |
|---|---|---|
issuer.allow_list required | list of {value} | Issuers whose tokens are accepted. Each must match the token’s iss claim exactly, trailing slash included. Values may use ${…}. |
audience.allow_list | list of {value} | When set, the token’s aud claim must contain one of these. |
http.tokens required | list | Where the tokens are: type (id_token, access_token, at+jwt, it+jwt, plain or jwt), method (header or body), name (the header, or the JSON or form field) and an optional prefix to strip, e.g. "Bearer ". When several are listed, all must be present and valid. |
jws.allowed_algorithms required | list of strings | RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512 or EdDSA. none is refused. |
jws.keys.sources.additional_jkus required | list of URLs | Up to 10 https URLs serving the issuer’s signing keys as a JWKS (the jwks_uri in its /.well-known/openid-configuration). |
jws.keys.identification | list | token_claims: [kid] — pick the key by the token’s kid, which devgate always does when the token has one. |
Result variables
After it runs, later rules can read what it decided:
-
actions.ngrok.jwt_validation.tokens— One entry per token: header and payload (the claims, e.g. tokens[0].payload.sub), signature, verified, location and location_property. -
actions.ngrok.jwt_validation.error.code / error.message— Why a token was refused, e.g. expired_token or invalid_issuer.
Behaviour
- A request without a valid token gets 401 with a WWW-Authenticate: Bearer header and never reaches your service.
- A token passes when an allowed algorithm and one of the JWKS keys sign it, an allowed issuer issued it, it’s meant for an allowed audience and it hasn’t expired: exp is required, nbf and iat are honoured, with 60 seconds of leeway for clock differences.
- The keys are cached for 15 minutes. A token whose kid isn’t among them makes devgate fetch the JWKS again (at most once a minute), so a key rotation doesn’t lock callers out.
- A token in the body needs a POST, PUT or PATCH request with a JSON or form body; the body still reaches your service unchanged.
- An at+jwt token must say typ: at+jwt, as RFC 9068 asks.
- JWKS URLs must be public https addresses.
Other actions
add-headers remove-headers compress-response basic-auth oauth openid-connect custom-response deny redirect url-rewrite restrict-ips rate-limit circuit-breaker verify-webhook http-request set-vars log close-connection forward-internal