> ## Documentation Index
> Fetch the complete documentation index at: https://ngrok.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# JWT Validation Action

> Validate JSON Web Tokens (JWT) on your endpoints before routing traffic to your upstream service.

export const ConfigChildren = ({children}) => {
  return <Accordion title="Show Child Properties">
      {children}
    </Accordion>;
};

export const ConfigField = ({title, type, cel = false, defaultValue = false, required = false, children}) => {
  const id = `config-${title.replace(/\.|\s|\*/g, "_")}`;
  return <div className="field pt-2.5 pb-5 my-2.5 border-gray-50 dark:border-gray-800/50 border-b" style={{
    scrollMarginTop: '120px'
  }} id={id}>
      <div className="flex font-mono group/param-head param-head break-all relative">
        <div className="flex-1 flex content-start py-0.5 mr-5">
          <div className="flex items-center flex-wrap gap-2">
            <div class="absolute -top-1.5">
              <a href={`#${id}`} className="-ml-10 flex items-center opacity-0 border-0 group-hover/param-head:opacity-100 py-2 [.expandable-content_&]:-ml-[2.1rem]" aria-label="Navigate to header">
                ​<div className="w-6 h-6 rounded-md flex items-center justify-center shadow-sm text-gray-400 dark:text-white/50 dark:bg-background-dark dark:brightness-[1.35] dark:ring-1 dark:hover::rightness-150 bg-white ring-1 ring-gray-400/30 dark:ring-gray-700/25 hover:ring-gray-400/60 dark:hover:ring-white/20">
                  <svg xmlns="http://www.w3.org/2000/svg" fill="gray" height="12px" viewBox="0 0 576 512"><path d="M0 256C0 167.6 71.6 96 160 96h72c13.3 0 24 10.7 24 24s-10.7 24-24 24H160C98.1 144 48 194.1 48 256s50.1 112 112 112h72c13.3 0 24 10.7 24 24s-10.7 24-24 24H160C71.6 416 0 344.4 0 256zm576 0c0 88.4-71.6 160-160 160H344c-13.3 0-24-10.7-24-24s10.7-24 24-24h72c61.9 0 112-50.1 112-112s-50.1-112-112-112H344c-13.3 0-24-10.7-24-24s10.7-24 24-24h72c88.4 0 160 71.6 160 160zM184 232H392c13.3 0 24 10.7 24 24s-10.7 24-24 24H184c-13.3 0-24-10.7-24-24s10.7-24 24-24z"></path></svg>
                </div>
              </a>
            </div>
            <div className="font-semibold text-primary dark:text-primary-light overflow-wrap-anywhere">{title}</div>
            <div className="inline items-center gap-2 text-xs font-medium [&_div]:inline [&_div]:mr-2 [&_div]:leading-5 [&_a]:inline [&_a]:mr-2 [&_a]:leading-5">
              {type && <div className="flex items-center px-2 py-0.5 rounded-md bg-gray-100/50 dark:bg-white/5 break-all">
                <span className="text-gray-600 dark:text-gray-200 !font-medium">{type}</span>
              </div>}
              {defaultValue && <div className="flex items-center px-2 py-0.5 rounded-md bg-gray-100/50 dark:bg-white/5 break-all">
                  <span class="text-gray-400 dark:text-gray-500">default:</span>
                  <span className="text-gray-600 dark:text-gray-200 !font-medium">{defaultValue}</span>
                </div>}
              {required && <div className="px-2 py-0.5 rounded-md bg-red-100/50 dark:bg-red-400/10 whitespace-nowrap">
                <span className="text-red-600 dark:text-red-300 !font-medium">Required</span>
              </div>}
              {cel && <a className="px-2 py-0.5 rounded-md !border-none bg-blue-100/50 dark:bg-blue-400/10 whitespace-nowrap" href="/traffic-policy/concepts/cel-interpolation">
                <span className="text-blue-600 dark:text-blue-300 !font-medium">Supports CEL</span>
              </a>}
            </div>
          </div>
        </div>
      </div>
      <div className="mt-4 prose-sm prose-gray dark:prose-invert [&_.prose>p:first-child]:mt-0 [&_.prose>p:last-child]:mb-0">
        {children}
      </div>
    </div>;
};

The **JWT Validation** Traffic Policy action enables you to validate JSON Web
Tokens (JWT) on your endpoints before routing traffic to your upstream service.

Guides for configuring this action with the following providers are available:

* [Auth0](/integrations/jwt-validation/auth0/)

A useful tool for working with JWTs is provided at [jwt.io](https://jwt.io).

## Configuration reference

The [Traffic Policy](/traffic-policy/) configuration
reference for this action.

### Supported phases

`on_http_request`

### Type

`jwt-validation`

### Configuration fields

<ConfigField title="issuer" type="object" required={true}>
  Configuration object for the Issuer(s) of the JWTs.

  <Expandable label="child properties">
    <ConfigField title="allow_list" type="array of objects" required={true}>
      List of allowed issuers. Minimum `1`.

      <Expandable label="child properties">
        <ConfigField title="allow_list[*].value" type="string" required={true} cel={true}>
          Issuer URL. This can be found in the <code>iss</code> claim after decoding the JWT or from the <code>/.well-known/openid-configuration</code> endpoint in your Identity Provider.
        </ConfigField>
      </Expandable>
    </ConfigField>
  </Expandable>
</ConfigField>

<ConfigField title="audience" type="object" required={false}>
  Configuration object for the Audience(s) of the JWTs.

  <Expandable label="child properties">
    <ConfigField title="allow_list" type="array of objects" required={false}>
      List of allowed audiences. Minimum `1`.

      <Expandable label="child properties">
        <ConfigField title="allow_list[*].value" type="string" required={false}>
          Audience claim value. This can be found in the <code>aud</code> claim after decoding the JWT or from the request used to create the token in the first place.
        </ConfigField>
      </Expandable>
    </ConfigField>
  </Expandable>
</ConfigField>

<ConfigField title="http" type="object" required={true}>
  Configuration object for the HTTP requests containing JWTs.

  <Expandable label="child properties">
    <ConfigField title="tokens" type="array of objects" required={true}>
      List of tokens to validate. Minimum `1`.

      <Expandable label="child properties">
        <ConfigField title="tokens[*].type" type="enum" required={true}>
          Type of the JWT, which acts as a hint about how ngrok should parse the token.

          <ConfigEnum>
            <ConfigEnumOption>`id_token`</ConfigEnumOption>
            <ConfigEnumOption>`access_token`</ConfigEnumOption>
            <ConfigEnumOption>`at+jwt`</ConfigEnumOption>
            <ConfigEnumOption>`it+jwt`</ConfigEnumOption>
            <ConfigEnumOption>`plain`</ConfigEnumOption>
            <ConfigEnumOption>`jwt`</ConfigEnumOption>
          </ConfigEnum>
        </ConfigField>

        <ConfigField title="tokens[*].method" type="enum" required={true}>
          Location in the request to expect the JWT.

          <ConfigEnum>
            <ConfigEnumOption>`header`</ConfigEnumOption>
            <ConfigEnumOption>`body`</ConfigEnumOption>
          </ConfigEnum>

          When choosing `header`, the <code>content-type</code> header must be set to either <code>application/json</code> or <code>application/x-www-form-urlencoded</code>.

          When choosing <code>body</code>, the method must be <code>POST</code>, <code>PUT</code>, or <code>PATCH</code>

          Including a token as a URL query parameter is not supported.
        </ConfigField>

        <ConfigField title="tokens[*].name" type="string" required={true} cel={true}>
          Name of the header or body field where the JWT is expected (Example: <code>"Authorization"</code>). This is not case sensitive.
        </ConfigField>

        <ConfigField title="tokens[*].prefix" type="string" cel={true}>
          Any prefix to strip from the header or body field before parsing the JWT (Example: <code>"Bearer "</code>).
        </ConfigField>
      </Expandable>
    </ConfigField>
  </Expandable>
</ConfigField>

<ConfigField title="jws" type="object" required={true}>
  Configuration object for signed JWTs (JWS).

  <Expandable label="child properties">
    <ConfigField title="allowed_algorithms" type="array of strings" required={true}>
      List of allowed signing algorithms. The value <code>none</code> is not supported here because it is insecure. Minimum `1`.
    </ConfigField>

    <ConfigField title="keys" type="array of objects" required={true}>
      Configuration for the JWT signing keys.

      <Expandable label="child properties">
        <ConfigField title="keys[*].identification" type="array of objects" required={false}>
          JWT metadata.

          <Expandable label="child properties">
            <ConfigField title="keys[*].identification[*].token_claims" type="array of strings" required={false}>
              List of claims present in this token. Supported values: \['kid']
            </ConfigField>
          </Expandable>
        </ConfigField>

        <ConfigField title="keys[*].sources" type="array of objects" required={true}>
          Configuration for the key material used to verify the signed JWTs.

          <Expandable label="child properties">
            <ConfigField title="keys[*].sources[*].additional_jkus" type="array of strings" required={true} cel={true}>
              List of URLs which serve the possible signing keys in JWKS format. These URLs are cached and refreshed roughly every 15 minutes.
            </ConfigField>
          </Expandable>
        </ConfigField>
      </Expandable>
    </ConfigField>
  </Expandable>
</ConfigField>

## Behavior

### Request validation

The request is allowed only if it has been correctly signed by the issuer and
the defined claims match.

For efficient validation of tokens, it is recommended to include the optional
`kid` claim in your JWTs and JWK payload.

Custom validation can be implemented in Traffic Policies via the
[`actions.ngrok.jwt_validation.tokens`](#action-result-variables) Action Result Variable and its
corresponding properties.

### Multiple issuers

You can specify multiple issuers for JWT validation. A request is
considered validated if it presents a JWT signed by any of the specified
issuers.

The issuer **must** exactly match the one provided in the JWT, including
any trailing slashes (`/`) present in the `iss` claim.

### Multiple audience claims

You can optionally specify one or more audience (`aud`) claims for JWT validation.

If present, the `aud` claim **must** contain at least one of the specified audience claims and
exactly match for validation to succeed.

### Multiple signing keys

You can provide multiple JSON Web Key Set (JWKS) URLs and signing algorithms.

During JWT validation the list of JWKS and algorithms provided will be used in
an attempt to validate the JWT. The list will be tried in order and is cached
for performance. The cache is refreshed roughly every 15 minutes.

### Multiple tokens

If multiple tokens are defined within the HTTP configuration parameter, all
tokens **must** be present in the request. If all tokens are not present, a
`401 Unauthorized` status code will be returned.

### Non-terminating action

This is a **Non-terminating action**. It does not return a response, and will allow Traffic Policy processing to continue to the next Action in the chain. All **Cloud Endpoint** Traffic Policies must end with a terminating action. This requirement does not apply to **Agent Endpoints**.

## Examples

### Basic example

The following [Traffic Policy](/traffic-policy/)
configuration is an example configuration of the `jwt-validation` action. For a
more real-world example, check out the [Auth0 guide](/integrations/jwt-validation/auth0/).

#### Example Traffic Policy document

<CodeGroup>
  ```yaml policy.yml theme={null}
  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 '
                - type: it+jwt
                  method: body
                  name: _id_token
            jws:
              allowed_algorithms:
                - RS256
                - ES256
              keys:
                sources:
                  additional_jkus:
                    - https://example.com/issuer/jku
  ```

  ```json policy.json theme={null}
  {
    "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 "
                  },
                  {
                    "type": "it+jwt",
                    "method": "body",
                    "name": "_id_token"
                  }
                ]
              },
              "jws": {
                "allowed_algorithms": [
                  "RS256",
                  "ES256"
                ],
                "keys": {
                  "sources": {
                    "additional_jkus": [
                      "https://example.com/issuer/jku"
                    ]
                  }
                }
              }
            }
          }
        ]
      }
    ]
  }
  ```
</CodeGroup>

#### Example request

```bash theme={null}
$ curl --request GET \
  --url http://example-api.ngrok.app/ \
  --header 'authorization: Bearer <VALID-JWT>'
```

```http theme={null}
HTTP/2 200 OK
content-type: text/html

...
```

In this example, a request is sent to the API with a valid JWT token in
the `Authorization` header with the `Bearer` prefix and getting back a `200 OK`
response.

## Action result variables

The following variables are made available for use in subsequent expressions and
CEL interpolations after the action has run. Variable values will only apply
to the last action execution, results are not concatenated.

<ConfigField title="actions.ngrok.jwt_validation.tokens" type="array of objects">
  The list of JSON Web Tokens (JWTs) processed by the action.

  <Expandable label="child properties">
    <ConfigField title="tokens[i].header" type="object">
      The header portion of the JWT, parsed into a key-value map containing metadata about the token.
    </ConfigField>

    <ConfigField title="tokens[i].location" type="string">
      The part of the HTTP request where the JWT was located (for example,{" "}
      <code>header</code>, <code>body</code>).
    </ConfigField>

    <ConfigField title="tokens[i].location_property" type="string">
      The specific header or body field that contained the JWT (for example,{" "}
      <code>"Authorization"</code>).
    </ConfigField>

    <ConfigField title="tokens[i].payload" type="object">
      The payload portion of the JWT, parsed into a key-value map
      representing the claims.
    </ConfigField>

    <ConfigField title="tokens[i].signature" type="string">
      The signature portion of the JWT, encoded in base64, used for
      verifying token integrity.
    </ConfigField>

    <ConfigField title="tokens[i].verified" type="boolean">
      Indicates whether the token passed verification. Returns{" "}
      <code>true</code> if verified successfully.
    </ConfigField>
  </Expandable>
</ConfigField>

<ConfigField title="actions.ngrok.jwt_validation.error.code" type="string">
  A machine-readable code describing an error that occurred during the
  action's execution.
</ConfigField>

<ConfigField title="actions.ngrok.jwt_validation.error.message" type="string">
  A human-readable message providing details about an error that occurred
  during the action's execution.
</ConfigField>
