jwt-validation

Lets a request through only with a valid JWT — signed by your issuer, for your audience, not expired. Everything else gets 401.

Phaseson_http_request
Terminating No — the next action runs after it.
Cost 10 Traffic Policy units per run · not on the Free plan

Example

policy.yaml
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