---
title: Token Verification
---

<BuiltinTable category={"tokens"} />

While OPA isn't responsible for issuing JWT tokens, Rego policies commonly
operate on HTTP requests which are authenticated using JWT tokens. Because
of this, it's important that Rego has native functionality to decode and
verify the contents of JWT tokens in order to enforce additional
authorization logic on requests.

Tokens often contain information about a user, which can be useful when
writing authorization policies. Other information contained in a token's
claims can include:

- Email or user ID. This can be used to look up the user in other
  datasets.
- Roles or groups. Often used for role-based access control.
- Locale, language and location. This can be used to enforce regional
  restrictions or provide localized messages.

Tokens can also contain any number of custom claims that are specific to
your organization and use case.

:::danger
Remember that JWT tokens **must** be verified before being trusted. Using
`io.jwt.decode()` alone is not enough without also verifying the token's
signature. [`io.jwt.decode_verify()`](#decode_verify) is the recommended
function to use as it both decodes and verifies the token while supporting
a wide range of signature algorithms.
:::

The input `string` is a JSON Web Token encoded with JWS Compact Serialization. JWE and JWS JSON Serialization are not supported. If nested signing was used, the `header`, `payload` and `signature` will represent the most deeply nested token.

## Examples

### `decode_verify`

`io.jwt.decode_verify()` is a built-in function that verifies and decodes
a JWT token using the provided constraints. The function accepts two
arguments:

- `jwt`: the JWT from the request to verify and decode.
- `constraints`: a map of constraints to apply when verifying the JWT.

The function can be seen as a combination of `io.jwt.verify_*` and
`io.jwt.decode()` built-ins. `io.jwt.decode_verify()` supports all of the
following algorithms:

- **HMAC Algorithms**: HS256, HS384, HS512
- **RSA Algorithms**: RS256, RS384, RS512
- **ECDSA Algorithms**: ES256, ES384, ES512
- **RSASSA-PSS Algorithms**: PS256, PS384, PS512

The function also supports using a symmetric key to verify the token,
though this is not recommended for production use.

:::danger
Remember that JWT tokens **must** be verified before being trusted. Using
`io.jwt.decode()` alone is not enough without also verifying the token's
signature. Using either a suitable `io.jwt.verify_*` function for your
token type or `io.jwt.decode_verify()` is required to ensure the token is
valid.
:::

`constraints` should contain either:

- `cert`: The [JWKS](https://datatracker.ietf.org/doc/html/rfc7517)
  or PEM-encoded certificate to use when verifying (RSA or ECDSA).
- `secret`: The secret key for HS256, HS384 and HS512 verification (not
  recommended for production use).

Optionally, `constraints` can also contain the following to further verify the token:

- `alg`: The JWA algorithm name to use. If it is absent then any algorithm that
  is compatible with the key is accepted.
- `aud`: Check the token was issued for the expected audience.
- `iss`: The issuer string. If it is present the only tokens with this issuer
  are accepted. If it is absent then any issuer is accepted.
- `time`: The time in nanoseconds to verify the token at. If this is present
  then the `exp` and `nbf` claims are compared against this value. If it is
  absent then they are compared against the current time.

The function returns a three element array consisting of:

1. A boolean indicating if the token was successfully verified.
2. A map of the token's headers.
3. A map of the token's claims.

For example, it might return:

```json
[
   true, // verified ok
   { "alg":"HS256", "typ":"JWT" }, // header
   { // claims
      "iss":"pki.example.com",
      "name":"John Doe",
      "sub":"1234567890"
   }
]
```

:::tip
<!-- note the code at the link is also here under tokens.go in case of link rot -->

If you'd like to generate a JWKS and signed JWT for testing below, you can
use the [example code here](https://go.dev/play/p/HMAPqDJM3jk).
:::

<PlaygroundExample dir={require.context('../_examples/io.jwt/decode_verify/symmetric')} />

<PlaygroundExample dir={require.context('../_examples/io.jwt/decode_verify/jwks')} />

<PlaygroundExample dir={require.context('../_examples/io.jwt/decode_verify/cert')} />

<PlaygroundExample dir={require.context('../_examples/io.jwt/decode_verify/jwks_time')} />

<PlaygroundExample dir={require.context('../_examples/io.jwt/decode_verify/jwks_groups')} />

### `verify_es256`

The example below uses the following token:

```rego
package jwt

es256_token := "eyJ0eXAiOiAiSldUIiwgImFsZyI6ICJFUzI1NiJ9.eyJuYmYiOiAxNDQ0NDc4NDAwLCAiaXNzIjogInh4eCJ9.lArczfN-pIL8oUU-7PU83u-zfXougXBZj6drFeKFsPEoVhy9WAyiZlRshYqjTSXdaw8yw2L-ovt4zTUZb2PWMg"
```

<RunSnippet id="token.rego"/>


This example shows a two-step process to verify the token signature and then decode it for
further checks of the payload content. This approach gives more flexibility in verifying only
the claims that the policy needs to enforce.

```rego
package jwt

jwks := `{
    "keys": [{
        "kty":"EC",
        "crv":"P-256",
        "x":"z8J91ghFy5o6f2xZ4g8LsLH7u2wEpT2ntj8loahnlsE",
        "y":"7bdeXLH61KrGWRdh7ilnbcGQACxykaPKfmBccTHIOUo"
    }]
}`
```

<RunSnippet id="jwks.rego"/>

<PlaygroundExample files="#jwks.rego #token.rego" dir={require.context("../_examples/io.jwt/verify_es256/jwks")} />

The following example will demonstrate verifying tokens using an X.509 Certificate
defined as:

```rego
package jwt

cert := `-----BEGIN CERTIFICATE-----
MIIBcDCCARagAwIBAgIJAMZmuGSIfvgzMAoGCCqGSM49BAMCMBMxETAPBgNVBAMM
CHdoYXRldmVyMB4XDTE4MDgxMDE0Mjg1NFoXDTE4MDkwOTE0Mjg1NFowEzERMA8G
A1UEAwwId2hhdGV2ZXIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATPwn3WCEXL
mjp/bFniDwuwsfu7bASlPae2PyWhqGeWwe23Xlyx+tSqxlkXYe4pZ23BkAAscpGj
yn5gXHExyDlKo1MwUTAdBgNVHQ4EFgQUElRjSoVgKjUqY5AXz2o74cLzzS8wHwYD
VR0jBBgwFoAUElRjSoVgKjUqY5AXz2o74cLzzS8wDwYDVR0TAQH/BAUwAwEB/zAK
BggqhkjOPQQDAgNIADBFAiEA4yQ/88ZrUX68c6kOe9G11u8NUaUzd8pLOtkKhniN
OHoCIHmNX37JOqTcTzGn2u9+c8NlnvZ0uDvsd1BmKPaUmjmm
-----END CERTIFICATE-----`
```

<RunSnippet id="cert.rego"/>

<PlaygroundExample files="#cert.rego #token.rego" dir={require.context("../_examples/io.jwt/verify_es256/cert")} />

