# Token Verification Built-ins

| Function | Description | Meta |
| --- | --- | --- |
| `io.jwt.decode` | `output := io.jwt.decode(jwt)`  Decodes a JSON Web Token and outputs it as an object.  **Arguments:**  `jwt` (string)  JWT token to decode  **Returns:**  `output` (array<object\[any: any\], object\[any: any\], string>)  `[header, payload, sig]`, where `header` and `payload` are objects; `sig` is the hexadecimal representation of the signature on the token. | SDK-dependent |
| `io.jwt.decode_verify` | `output := io.jwt.decode_verify(jwt, constraints)`  Verifies a JWT signature under parameterized constraints and decodes the claims if it is valid. Supports the following algorithms: HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES512, PS256, PS384, PS512, and EdDSA.  **Arguments:**  `jwt` (string)  JWT token whose signature is to be verified and whose claims are to be checked  `constraints` (object\[string: any\])  claim verification constraints  **Returns:**  `output` (array<boolean, object\[any: any\], object\[any: any\]>)  `[valid, header, payload]`: if the input token is verified and meets the requirements of `constraints` then `valid` is `true`; `header` and `payload` are objects containing the JOSE header and the JWT claim set; otherwise, `valid` is `false`, `header` and `payload` are `{}` | SDK-dependent |
| `io.jwt.verify_eddsa` | `result := io.jwt.verify_eddsa(jwt, certificate)`  Verifies if an EdDSA JWT signature is valid.  **Arguments:**  `jwt` (string)  JWT token whose signature is to be verified  `certificate` (string)  PEM encoded certificate, PEM encoded public key, or the JWK key (set) used to verify the signature  **Returns:**  `result` (boolean)  `true` if the signature is valid, `false` otherwise | [v1.8.0](https://github.com/open-policy-agent/opa/releases/v1.8.0) SDK-dependent |
| `io.jwt.verify_es256` | `result := io.jwt.verify_es256(jwt, certificate)`  Verifies if a ES256 JWT signature is valid.  **Arguments:**  `jwt` (string)  JWT token whose signature is to be verified  `certificate` (string)  PEM encoded certificate, PEM encoded public key, or the JWK key (set) used to verify the signature  **Returns:**  `result` (boolean)  `true` if the signature is valid, `false` otherwise | SDK-dependent |
| `io.jwt.verify_es384` | `result := io.jwt.verify_es384(jwt, certificate)`  Verifies if a ES384 JWT signature is valid.  **Arguments:**  `jwt` (string)  JWT token whose signature is to be verified  `certificate` (string)  PEM encoded certificate, PEM encoded public key, or the JWK key (set) used to verify the signature  **Returns:**  `result` (boolean)  `true` if the signature is valid, `false` otherwise | [v0.20.0](https://github.com/open-policy-agent/opa/releases/v0.20.0) SDK-dependent |
| `io.jwt.verify_es512` | `result := io.jwt.verify_es512(jwt, certificate)`  Verifies if a ES512 JWT signature is valid.  **Arguments:**  `jwt` (string)  JWT token whose signature is to be verified  `certificate` (string)  PEM encoded certificate, PEM encoded public key, or the JWK key (set) used to verify the signature  **Returns:**  `result` (boolean)  `true` if the signature is valid, `false` otherwise | [v0.20.0](https://github.com/open-policy-agent/opa/releases/v0.20.0) SDK-dependent |
| `io.jwt.verify_hs256` | `result := io.jwt.verify_hs256(jwt, secret)`  Verifies if a HS256 (secret) JWT signature is valid.  **Arguments:**  `jwt` (string)  JWT token whose signature is to be verified  `secret` (string)  plain text secret used to verify the signature  **Returns:**  `result` (boolean)  `true` if the signature is valid, `false` otherwise | SDK-dependent |
| `io.jwt.verify_hs384` | `result := io.jwt.verify_hs384(jwt, secret)`  Verifies if a HS384 (secret) JWT signature is valid.  **Arguments:**  `jwt` (string)  JWT token whose signature is to be verified  `secret` (string)  plain text secret used to verify the signature  **Returns:**  `result` (boolean)  `true` if the signature is valid, `false` otherwise | [v0.20.0](https://github.com/open-policy-agent/opa/releases/v0.20.0) SDK-dependent |
| `io.jwt.verify_hs512` | `result := io.jwt.verify_hs512(jwt, secret)`  Verifies if a HS512 (secret) JWT signature is valid.  **Arguments:**  `jwt` (string)  JWT token whose signature is to be verified  `secret` (string)  plain text secret used to verify the signature  **Returns:**  `result` (boolean)  `true` if the signature is valid, `false` otherwise | [v0.20.0](https://github.com/open-policy-agent/opa/releases/v0.20.0) SDK-dependent |
| `io.jwt.verify_ps256` | `result := io.jwt.verify_ps256(jwt, certificate)`  Verifies if a PS256 JWT signature is valid.  **Arguments:**  `jwt` (string)  JWT token whose signature is to be verified  `certificate` (string)  PEM encoded certificate, PEM encoded public key, or the JWK key (set) used to verify the signature  **Returns:**  `result` (boolean)  `true` if the signature is valid, `false` otherwise | SDK-dependent |
| `io.jwt.verify_ps384` | `result := io.jwt.verify_ps384(jwt, certificate)`  Verifies if a PS384 JWT signature is valid.  **Arguments:**  `jwt` (string)  JWT token whose signature is to be verified  `certificate` (string)  PEM encoded certificate, PEM encoded public key, or the JWK key (set) used to verify the signature  **Returns:**  `result` (boolean)  `true` if the signature is valid, `false` otherwise | [v0.20.0](https://github.com/open-policy-agent/opa/releases/v0.20.0) SDK-dependent |
| `io.jwt.verify_ps512` | `result := io.jwt.verify_ps512(jwt, certificate)`  Verifies if a PS512 JWT signature is valid.  **Arguments:**  `jwt` (string)  JWT token whose signature is to be verified  `certificate` (string)  PEM encoded certificate, PEM encoded public key, or the JWK key (set) used to verify the signature  **Returns:**  `result` (boolean)  `true` if the signature is valid, `false` otherwise | [v0.20.0](https://github.com/open-policy-agent/opa/releases/v0.20.0) SDK-dependent |
| `io.jwt.verify_rs256` | `result := io.jwt.verify_rs256(jwt, certificate)`  Verifies if a RS256 JWT signature is valid.  **Arguments:**  `jwt` (string)  JWT token whose signature is to be verified  `certificate` (string)  PEM encoded certificate, PEM encoded public key, or the JWK key (set) used to verify the signature  **Returns:**  `result` (boolean)  `true` if the signature is valid, `false` otherwise | SDK-dependent |
| `io.jwt.verify_rs384` | `result := io.jwt.verify_rs384(jwt, certificate)`  Verifies if a RS384 JWT signature is valid.  **Arguments:**  `jwt` (string)  JWT token whose signature is to be verified  `certificate` (string)  PEM encoded certificate, PEM encoded public key, or the JWK key (set) used to verify the signature  **Returns:**  `result` (boolean)  `true` if the signature is valid, `false` otherwise | [v0.20.0](https://github.com/open-policy-agent/opa/releases/v0.20.0) SDK-dependent |
| `io.jwt.verify_rs512` | `result := io.jwt.verify_rs512(jwt, certificate)`  Verifies if a RS512 JWT signature is valid.  **Arguments:**  `jwt` (string)  JWT token whose signature is to be verified  `certificate` (string)  PEM encoded certificate, PEM encoded public key, or the JWK key (set) used to verify the signature  **Returns:**  `result` (boolean)  `true` if the signature is valid, `false` otherwise | [v0.20.0](https://github.com/open-policy-agent/opa/releases/v0.20.0) SDK-dependent |

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:

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

tip

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).

Verification with a shared symmetric key

warning

This example uses a symmetric key to verify the token. This is not recommended for production use. Please see the examples below using `JWKs` or PEM-encoded certificates more examples.

Sometimes when working with tools like [JWT.io](https://www.jwt.io/) it can be useful to decode and verify JWT tokens signed with a symmetric key just to see what the output of `io.jwt.decode_verify()` looks like.

The not-so-secret symmetric key `password` was used to sign the token provided in the input for the policy below. We can see that the claims in this example contains `secret` and `iss` only. This means that the validity period of the token is not checked, nor is the audience or the algorithm used to sign it.

policy.rego

```
package playimport rego.v1default allow := falseallow if {	# perform checks on the claims...	verified_claims.sub == "1234567890"}verified_claims := claims if {	[verified, _, claims] := io.jwt.decode_verify(		input.token,		{			"secret": "password",			"iss": "pki.example.com",		},	)	verified == true}
```

Output

{
  "allow": true,
  "verified\_claims": {
    "iss": "pki.example.com",
    "name": "John Doe",
    "sub": "1234567890"
  }
}

input.json

```
{  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaXNzIjoicGtpLmV4YW1wbGUuY29tIn0.EiAS-4_ecAe3Fx3GDzZkvNPmhIaDQTHnmpLAHdWWe60"}
```

data.json

```
{}
```

[Open in OPA Playground](https://play.openpolicyagent.org/?state=eyJpIjoie1xuICBcInRva2VuXCI6IFwiZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnpkV0lpT2lJeE1qTTBOVFkzT0Rrd0lpd2libUZ0WlNJNklrcHZhRzRnUkc5bElpd2lhWE56SWpvaWNHdHBMbVY0WVcxd2JHVXVZMjl0SW4wLkVpQVMtNF9lY0FlM0Z4M0dEelprdk5QbWhJYURRVEhubXBMQUhkV1dlNjBcIlxufSIsImQiOiJ7fSIsInAiOiJwYWNrYWdlIHBsYXlcblxuaW1wb3J0IHJlZ28udjFcblxuZGVmYXVsdCBhbGxvdyA6PSBmYWxzZVxuXG5hbGxvdyBpZiB7XG5cdCMgcGVyZm9ybSBjaGVja3Mgb24gdGhlIGNsYWltcy4uLlxuXHR2ZXJpZmllZF9jbGFpbXMuc3ViID09IFwiMTIzNDU2Nzg5MFwiXG59XG5cbnZlcmlmaWVkX2NsYWltcyA6PSBjbGFpbXMgaWYge1xuXHRbdmVyaWZpZWQsIF8sIGNsYWltc10gOj0gaW8uand0LmRlY29kZV92ZXJpZnkoXG5cdFx0aW5wdXQudG9rZW4sXG5cdFx0e1xuXHRcdFx0XCJzZWNyZXRcIjogXCJwYXNzd29yZFwiLFxuXHRcdFx0XCJpc3NcIjogXCJwa2kuZXhhbXBsZS5jb21cIixcblx0XHR9LFxuXHQpXG5cblx0dmVyaWZpZWQgPT0gdHJ1ZVxufVxuIn0=)

Verification with a JSON Web Key Set (JWKS)

This example builds on the JWKS example above

Note: You can generate your own JWKS and signed JWT for testing using the example code [here](https://go.dev/play/p/HMAPqDJM3jk).

policy.rego

```
package playimport rego.v1jwks := `{  "keys": [    {      "alg": "ES256",      "crv": "P-256",      "kid": "my-key-id",      "kty": "EC",      "use": "sig",      "x": "iTV4PECbWuDaNBMTLmwH0jwBTD3xUXR0S-VWsCYv8Gc",      "y": "-Cnw8d0XyQztrPZpynrFn8t10lyEb6oWqWcLJWPUB5A"    }  ]}`allow if {	# perform checks on the verified claims...	verified_claims}verified_claims := claims if {	[verified, _, claims] := io.jwt.decode_verify(		input.token,		{			"cert": jwks,			"iss": "pki.example.com",		},	)	verified == true}
```

Output

{
  "allow": true,
  "jwks": "{\\n  \\"keys\\": \[\\n    {\\n      \\"alg\\": \\"ES256\\",\\n      \\"crv\\": \\"P-256\\",\\n      \\"kid\\": \\"my-key-id\\",\\n      \\"kty\\": \\"EC\\",\\n      \\"use\\": \\"sig\\",\\n      \\"x\\": \\"iTV4PECbWuDaNBMTLmwH0jwBTD3xUXR0S-VWsCYv8Gc\\",\\n      \\"y\\": \\"-Cnw8d0XyQztrPZpynrFn8t10lyEb6oWqWcLJWPUB5A\\"\\n    }\\n  \]\\n}",
  "verified\_claims": {
    "iss": "pki.example.com"
  }
}

input.json

```
{  "token": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJwa2kuZXhhbXBsZS5jb20ifQ.ViJTHHv5FuJM9LsRrTpzts6tZkN8deKiu5x49-M8-nq6Rs6ta-Wn8fN_YVLlpZvwhFu_yfxpfUGhBRc33QSSsw"}
```

data.json

```
{}
```

[Open in OPA Playground](https://play.openpolicyagent.org/?state=eyJpIjoie1xuICBcInRva2VuXCI6IFwiZXlKaGJHY2lPaUpGVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnBjM01pT2lKd2Eya3VaWGhoYlhCc1pTNWpiMjBpZlEuVmlKVEhIdjVGdUpNOUxzUnJUcHp0czZ0WmtOOGRlS2l1NXg0OS1NOC1ucTZSczZ0YS1XbjhmTl9ZVkxscFp2d2hGdV95ZnhwZlVHaEJSYzMzUVNTc3dcIlxufSIsImQiOiJ7fSIsInAiOiJwYWNrYWdlIHBsYXlcblxuaW1wb3J0IHJlZ28udjFcblxuandrcyA6PSBge1xuICBcImtleXNcIjogW1xuICAgIHtcbiAgICAgIFwiYWxnXCI6IFwiRVMyNTZcIixcbiAgICAgIFwiY3J2XCI6IFwiUC0yNTZcIixcbiAgICAgIFwia2lkXCI6IFwibXkta2V5LWlkXCIsXG4gICAgICBcImt0eVwiOiBcIkVDXCIsXG4gICAgICBcInVzZVwiOiBcInNpZ1wiLFxuICAgICAgXCJ4XCI6IFwiaVRWNFBFQ2JXdURhTkJNVExtd0gwandCVEQzeFVYUjBTLVZXc0NZdjhHY1wiLFxuICAgICAgXCJ5XCI6IFwiLUNudzhkMFh5UXp0clBacHluckZuOHQxMGx5RWI2b1dxV2NMSldQVUI1QVwiXG4gICAgfVxuICBdXG59YFxuXG5hbGxvdyBpZiB7XG5cdCMgcGVyZm9ybSBjaGVja3Mgb24gdGhlIHZlcmlmaWVkIGNsYWltcy4uLlxuXHR2ZXJpZmllZF9jbGFpbXNcbn1cblxudmVyaWZpZWRfY2xhaW1zIDo9IGNsYWltcyBpZiB7XG5cdFt2ZXJpZmllZCwgXywgY2xhaW1zXSA6PSBpby5qd3QuZGVjb2RlX3ZlcmlmeShcblx0XHRpbnB1dC50b2tlbixcblx0XHR7XG5cdFx0XHRcImNlcnRcIjogandrcyxcblx0XHRcdFwiaXNzXCI6IFwicGtpLmV4YW1wbGUuY29tXCIsXG5cdFx0fSxcblx0KVxuXG5cdHZlcmlmaWVkID09IHRydWVcbn1cbiJ9)

Verification with a PEM-encoded certificate

Some users may prefer to use a certificate to verify the JWT token. This example shows how to use a certificate to verify the JWT. Much like the other examples, it only checks the `iss` claim.

Note: You can generate your own certificate and signed JWT for testing using the example code [here](https://go.dev/play/p/HMAPqDJM3jk).

policy.rego

```
package playimport rego.v1cert := `-----BEGIN CERTIFICATE-----MIIBMzCB2aADAgECAgEBMAoGCCqGSM49BAMCMBIxEDAOBgNVBAoTB0V4YW1wbGUwHhcNMDkxMTEwMjMwMDAwWhcNMTAxMTEwMjMwMDAwWjASMRAwDgYDVQQKEwdFeGFtcGxlMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERgI9efDtzy0QubqeMgYPyD+kGWtw2JueCpORUB0hOecwnO5HjPiZ3OsE5wIvwzt8fJzbZFHBoKx5GfbUCiOlpKMgMB4wDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwCgYIKoZIzj0EAwIDSQAwRgIhAIQNOE/SCRr2pkW4XCGIaHuNO6oXHDp/HThPxaHfyTmPAiEA8uPj91awzzdWxOI1W2BMAnR1VlCHTaaoGCaWUjTo6Sc=-----END CERTIFICATE-----`default allow := falseallow if {	# perform additional checks as required	verified_claims}verified_claims := claims if {	[verified, _, claims] := io.jwt.decode_verify(		input.token,		{			"cert": cert,			"iss": "pki.example.com",		},	)	verified == true}
```

Output

{
  "allow": true,
  "cert": "-----BEGIN CERTIFICATE-----\\nMIIBMzCB2aADAgECAgEBMAoGCCqGSM49BAMCMBIxEDAOBgNVBAoTB0V4YW1wbGUw\\nHhcNMDkxMTEwMjMwMDAwWhcNMTAxMTEwMjMwMDAwWjASMRAwDgYDVQQKEwdFeGFt\\ncGxlMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERgI9efDtzy0QubqeMgYPyD+k\\nGWtw2JueCpORUB0hOecwnO5HjPiZ3OsE5wIvwzt8fJzbZFHBoKx5GfbUCiOlpKMg\\nMB4wDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwCgYIKoZIzj0EAwIDSQAw\\nRgIhAIQNOE/SCRr2pkW4XCGIaHuNO6oXHDp/HThPxaHfyTmPAiEA8uPj91awzzdW\\nxOI1W2BMAnR1VlCHTaaoGCaWUjTo6Sc=\\n-----END CERTIFICATE-----\\n",
  "verified\_claims": {
    "iss": "pki.example.com"
  }
}

input.json

```
{  "token": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJwa2kuZXhhbXBsZS5jb20ifQ.ADOSFDJMBu7EBjiDa4-_uoI0PeAnAz8Ap8-GjsoKb_spdWCbGJR4QxBTMoBfoPbA1HajGinIgbbbL8yaqBlzKQ"}
```

data.json

```
{}
```

[Open in OPA Playground](https://play.openpolicyagent.org/?state=eyJpIjoie1xuICBcInRva2VuXCI6IFwiZXlKaGJHY2lPaUpGVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnBjM01pT2lKd2Eya3VaWGhoYlhCc1pTNWpiMjBpZlEuQURPU0ZESk1CdTdFQmppRGE0LV91b0kwUGVBbkF6OEFwOC1HanNvS2Jfc3BkV0NiR0pSNFF4QlRNb0Jmb1BiQTFIYWpHaW5JZ2JiYkw4eWFxQmx6S1FcIlxufSIsImQiOiJ7fSIsInAiOiJwYWNrYWdlIHBsYXlcblxuaW1wb3J0IHJlZ28udjFcblxuY2VydCA6PSBgLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tXG5NSUlCTXpDQjJhQURBZ0VDQWdFQk1Bb0dDQ3FHU000OUJBTUNNQkl4RURBT0JnTlZCQW9UQjBWNFlXMXdiR1V3XG5IaGNOTURreE1URXdNak13TURBd1doY05NVEF4TVRFd01qTXdNREF3V2pBU01SQXdEZ1lEVlFRS0V3ZEZlR0Z0XG5jR3hsTUZrd0V3WUhLb1pJemowQ0FRWUlLb1pJemowREFRY0RRZ0FFUmdJOWVmRHR6eTBRdWJxZU1nWVB5RCtrXG5HV3R3Mkp1ZUNwT1JVQjBoT2Vjd25PNUhqUGlaM09zRTV3SXZ3enQ4Zkp6YlpGSEJvS3g1R2ZiVUNpT2xwS01nXG5NQjR3RGdZRFZSMFBBUUgvQkFRREFnV2dNQXdHQTFVZEV3RUIvd1FDTUFBd0NnWUlLb1pJemowRUF3SURTUUF3XG5SZ0loQUlRTk9FL1NDUnIycGtXNFhDR0lhSHVOTzZvWEhEcC9IVGhQeGFIZnlUbVBBaUVBOHVQajkxYXd6emRXXG54T0kxVzJCTUFuUjFWbENIVGFhb0dDYVdValRvNlNjPVxuLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLVxuYFxuXG5kZWZhdWx0IGFsbG93IDo9IGZhbHNlXG5cbmFsbG93IGlmIHtcblx0IyBwZXJmb3JtIGFkZGl0aW9uYWwgY2hlY2tzIGFzIHJlcXVpcmVkXG5cdHZlcmlmaWVkX2NsYWltc1xufVxuXG52ZXJpZmllZF9jbGFpbXMgOj0gY2xhaW1zIGlmIHtcblx0W3ZlcmlmaWVkLCBfLCBjbGFpbXNdIDo9IGlvLmp3dC5kZWNvZGVfdmVyaWZ5KFxuXHRcdGlucHV0LnRva2VuLFxuXHRcdHtcblx0XHRcdFwiY2VydFwiOiBjZXJ0LFxuXHRcdFx0XCJpc3NcIjogXCJwa2kuZXhhbXBsZS5jb21cIixcblx0XHR9LFxuXHQpXG5cblx0dmVyaWZpZWQgPT0gdHJ1ZVxufVxuIn0=)

JWKS and time-of-use verification

In addition to verifying the JWT token's signature and issuer, this example also checks the token's validity period. The token in the example is valid for 2020-2030, try it out in the playground and use the example code [on the Go Playground](https://go.dev/play/p/HMAPqDJM3jk) to generate your own data to test with.

policy.rego

```
package playimport rego.v1jwks := `{    "keys": [        {            "alg": "ES256",            "crv": "P-256",            "kid": "my-key-id",            "kty": "EC",            "use": "sig",            "x": "Uv7zcspR68KLcqZJDV5WYd946uHTeOFhHVi0hAkqkWI",            "y": "YExfQqSyCo3LlX1K7F9NCTQjcNBNRWAZqsbWtNNHwTU"        }    ]}`verified_claims := claims if {	[verified, _, claims] := io.jwt.decode_verify(		input.token,		{			"cert": jwks,			"iss": "pki.example.com",			# a time in 2024			"time": 1720109779675634700,		},	)	verified == true}verified_claims_future := claims if {	[verified, _, claims] := io.jwt.decode_verify(		input.token,		{			"cert": jwks,			"iss": "pki.example.com",			# a time in the future			"time": 4875783401643188000,		},	)	verified == true}default allow := falseallow if {	verified_claims}# default is used since token is not verifieddefault allow_future := falseallow_future if {	# unset, since the token is not verified	verified_claims_future}
```

Output

{
  "allow": true,
  "allow\_future": false,
  "jwks": "{\\n    \\"keys\\": \[\\n        {\\n            \\"alg\\": \\"ES256\\",\\n            \\"crv\\": \\"P-256\\",\\n            \\"kid\\": \\"my-key-id\\",\\n            \\"kty\\": \\"EC\\",\\n            \\"use\\": \\"sig\\",\\n            \\"x\\": \\"Uv7zcspR68KLcqZJDV5WYd946uHTeOFhHVi0hAkqkWI\\",\\n            \\"y\\": \\"YExfQqSyCo3LlX1K7F9NCTQjcNBNRWAZqsbWtNNHwTU\\"\\n        }\\n    \]\\n}",
  "verified\_claims": {
    "exp": 1893456000,
    "iss": "pki.example.com",
    "nbf": 1577836800
  }
}

input.json

```
{  "token": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE4OTM0NTYwMDAsImlzcyI6InBraS5leGFtcGxlLmNvbSIsIm5iZiI6MTU3NzgzNjgwMH0.AVJC13glrKi92cIoH7ZXInDxL2ulikkOepL7LbTlAjApUlj_To8T9m4lf8Z-VoxfxLF5vVneQinn7q-niN2TQQ"}
```

data.json

```
{}
```

[Open in OPA Playground](https://play.openpolicyagent.org/?state=eyJpIjoie1xuICBcInRva2VuXCI6IFwiZXlKaGJHY2lPaUpGVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SmxlSEFpT2pFNE9UTTBOVFl3TURBc0ltbHpjeUk2SW5CcmFTNWxlR0Z0Y0d4bExtTnZiU0lzSW01aVppSTZNVFUzTnpnek5qZ3dNSDAuQVZKQzEzZ2xyS2k5MmNJb0g3WlhJbkR4TDJ1bGlra09lcEw3TGJUbEFqQXBVbGpfVG84VDltNGxmOFotVm94ZnhMRjV2Vm5lUWlubjdxLW5pTjJUUVFcIlxufSIsImQiOiJ7fSIsInAiOiJwYWNrYWdlIHBsYXlcblxuaW1wb3J0IHJlZ28udjFcblxuandrcyA6PSBge1xuICAgIFwia2V5c1wiOiBbXG4gICAgICAgIHtcbiAgICAgICAgICAgIFwiYWxnXCI6IFwiRVMyNTZcIixcbiAgICAgICAgICAgIFwiY3J2XCI6IFwiUC0yNTZcIixcbiAgICAgICAgICAgIFwia2lkXCI6IFwibXkta2V5LWlkXCIsXG4gICAgICAgICAgICBcImt0eVwiOiBcIkVDXCIsXG4gICAgICAgICAgICBcInVzZVwiOiBcInNpZ1wiLFxuICAgICAgICAgICAgXCJ4XCI6IFwiVXY3emNzcFI2OEtMY3FaSkRWNVdZZDk0NnVIVGVPRmhIVmkwaEFrcWtXSVwiLFxuICAgICAgICAgICAgXCJ5XCI6IFwiWUV4ZlFxU3lDbzNMbFgxSzdGOU5DVFFqY05CTlJXQVpxc2JXdE5OSHdUVVwiXG4gICAgICAgIH1cbiAgICBdXG59YFxuXG52ZXJpZmllZF9jbGFpbXMgOj0gY2xhaW1zIGlmIHtcblx0W3ZlcmlmaWVkLCBfLCBjbGFpbXNdIDo9IGlvLmp3dC5kZWNvZGVfdmVyaWZ5KFxuXHRcdGlucHV0LnRva2VuLFxuXHRcdHtcblx0XHRcdFwiY2VydFwiOiBqd2tzLFxuXHRcdFx0XCJpc3NcIjogXCJwa2kuZXhhbXBsZS5jb21cIixcblx0XHRcdCMgYSB0aW1lIGluIDIwMjRcblx0XHRcdFwidGltZVwiOiAxNzIwMTA5Nzc5Njc1NjM0NzAwLFxuXHRcdH0sXG5cdClcblxuXHR2ZXJpZmllZCA9PSB0cnVlXG59XG5cbnZlcmlmaWVkX2NsYWltc19mdXR1cmUgOj0gY2xhaW1zIGlmIHtcblx0W3ZlcmlmaWVkLCBfLCBjbGFpbXNdIDo9IGlvLmp3dC5kZWNvZGVfdmVyaWZ5KFxuXHRcdGlucHV0LnRva2VuLFxuXHRcdHtcblx0XHRcdFwiY2VydFwiOiBqd2tzLFxuXHRcdFx0XCJpc3NcIjogXCJwa2kuZXhhbXBsZS5jb21cIixcblx0XHRcdCMgYSB0aW1lIGluIHRoZSBmdXR1cmVcblx0XHRcdFwidGltZVwiOiA0ODc1NzgzNDAxNjQzMTg4MDAwLFxuXHRcdH0sXG5cdClcblxuXHR2ZXJpZmllZCA9PSB0cnVlXG59XG5cbmRlZmF1bHQgYWxsb3cgOj0gZmFsc2VcblxuYWxsb3cgaWYge1xuXHR2ZXJpZmllZF9jbGFpbXNcbn1cblxuIyBkZWZhdWx0IGlzIHVzZWQgc2luY2UgdG9rZW4gaXMgbm90IHZlcmlmaWVkXG5kZWZhdWx0IGFsbG93X2Z1dHVyZSA6PSBmYWxzZVxuXG5hbGxvd19mdXR1cmUgaWYge1xuXHQjIHVuc2V0LCBzaW5jZSB0aGUgdG9rZW4gaXMgbm90IHZlcmlmaWVkXG5cdHZlcmlmaWVkX2NsYWltc19mdXR1cmVcbn1cbiJ9)

Validating a token's groups or roles

So far, all the examples on this page have used the `constraints` parameter to specify the claims that should be checked and their values. The functionality covered by `constraints` represents the core checks when verifying a JWT token.

JWT tokens however can contain a lot more information than just the claims specified in the `constraints` parameter. This example makes an additional check in the `allow` rule to ensure that the token's groups claim contains the expected value.

policy.rego

```
package playimport rego.v1jwks := `{  "keys": [    {      "alg": "ES256",      "crv": "P-256",      "kid": "my-key-id",      "kty": "EC",      "use": "sig",      "x": "hV6Tel-bKwtnfgLAn9aPCe24WgKpnoZwDXKbAKdjUV4",      "y": "xmIK_KmwlJ_jrWAaTvdfvqvAYuxDH_2e4dbIzPQmnFM"    }  ]}`default allow := falseallow if {	"developers" in verified_claims.groups}verified_claims := claims if {	[verified, _, claims] := io.jwt.decode_verify(		input.token,		{			"cert": jwks,			"iss": "pki.example.com",		},	)	verified == true}
```

Output

{
  "allow": true,
  "jwks": "{\\n  \\"keys\\": \[\\n    {\\n      \\"alg\\": \\"ES256\\",\\n      \\"crv\\": \\"P-256\\",\\n      \\"kid\\": \\"my-key-id\\",\\n      \\"kty\\": \\"EC\\",\\n      \\"use\\": \\"sig\\",\\n      \\"x\\": \\"hV6Tel-bKwtnfgLAn9aPCe24WgKpnoZwDXKbAKdjUV4\\",\\n      \\"y\\": \\"xmIK\_KmwlJ\_jrWAaTvdfvqvAYuxDH\_2e4dbIzPQmnFM\\"\\n    }\\n  \]\\n}",
  "verified\_claims": {
    "groups": \[
      "developers"
    \],
    "iss": "pki.example.com"
  }
}

input.json

```
{  "token": "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJncm91cHMiOlsiZGV2ZWxvcGVycyJdLCJpc3MiOiJwa2kuZXhhbXBsZS5jb20ifQ.hf-ew6HF_ziZ2H02UAHyCWekqpM9n0ET9bawh_T8gj3PiVROKmCDPz7d7sJev7bwASOTgKlXum2TE_j21x2zmw"}
```

data.json

```
{}
```

[Open in OPA Playground](https://play.openpolicyagent.org/?state=eyJpIjoie1xuICBcInRva2VuXCI6IFwiZXlKaGJHY2lPaUpGVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5Sm5jbTkxY0hNaU9sc2laR1YyWld4dmNHVnljeUpkTENKcGMzTWlPaUp3YTJrdVpYaGhiWEJzWlM1amIyMGlmUS5oZi1ldzZIRl96aVoySDAyVUFIeUNXZWtxcE05bjBFVDliYXdoX1Q4Z2ozUGlWUk9LbUNEUHo3ZDdzSmV2N2J3QVNPVGdLbFh1bTJURV9qMjF4Mnptd1wiXG59IiwiZCI6Int9IiwicCI6InBhY2thZ2UgcGxheVxuXG5pbXBvcnQgcmVnby52MVxuXG5qd2tzIDo9IGB7XG4gIFwia2V5c1wiOiBbXG4gICAge1xuICAgICAgXCJhbGdcIjogXCJFUzI1NlwiLFxuICAgICAgXCJjcnZcIjogXCJQLTI1NlwiLFxuICAgICAgXCJraWRcIjogXCJteS1rZXktaWRcIixcbiAgICAgIFwia3R5XCI6IFwiRUNcIixcbiAgICAgIFwidXNlXCI6IFwic2lnXCIsXG4gICAgICBcInhcIjogXCJoVjZUZWwtYkt3dG5mZ0xBbjlhUENlMjRXZ0twbm9ad0RYS2JBS2RqVVY0XCIsXG4gICAgICBcInlcIjogXCJ4bUlLX0ttd2xKX2pyV0FhVHZkZnZxdkFZdXhESF8yZTRkYkl6UFFtbkZNXCJcbiAgICB9XG4gIF1cbn1gXG5cbmRlZmF1bHQgYWxsb3cgOj0gZmFsc2VcblxuYWxsb3cgaWYge1xuXHRcImRldmVsb3BlcnNcIiBpbiB2ZXJpZmllZF9jbGFpbXMuZ3JvdXBzXG59XG5cbnZlcmlmaWVkX2NsYWltcyA6PSBjbGFpbXMgaWYge1xuXHRbdmVyaWZpZWQsIF8sIGNsYWltc10gOj0gaW8uand0LmRlY29kZV92ZXJpZnkoXG5cdFx0aW5wdXQudG9rZW4sXG5cdFx0e1xuXHRcdFx0XCJjZXJ0XCI6IGp3a3MsXG5cdFx0XHRcImlzc1wiOiBcInBraS5leGFtcGxlLmNvbVwiLFxuXHRcdH0sXG5cdClcblxuXHR2ZXJpZmllZCA9PSB0cnVlXG59XG4ifQ==)

### `verify_es256`

The example below uses the following token:

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

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.

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

JWKS Verify

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.

data.json

```
{}
```

input.json

```
{}
```

```
package jwtresult.verify := io.jwt.verify_es256(es256_token, jwks) # Verify the token with the JWKSresult.payload := io.jwt.decode(es256_token)            # Decode the tokenresult.check := result.payload[1].iss == "xxx"          # Ensure the issuer (`iss`) claim is the expected value
```

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

```
package jwtcert := `-----BEGIN CERTIFICATE-----MIIBcDCCARagAwIBAgIJAMZmuGSIfvgzMAoGCCqGSM49BAMCMBMxETAPBgNVBAMMCHdoYXRldmVyMB4XDTE4MDgxMDE0Mjg1NFoXDTE4MDkwOTE0Mjg1NFowEzERMA8GA1UEAwwId2hhdGV2ZXIwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATPwn3WCEXLmjp/bFniDwuwsfu7bASlPae2PyWhqGeWwe23Xlyx+tSqxlkXYe4pZ23BkAAscpGjyn5gXHExyDlKo1MwUTAdBgNVHQ4EFgQUElRjSoVgKjUqY5AXz2o74cLzzS8wHwYDVR0jBBgwFoAUElRjSoVgKjUqY5AXz2o74cLzzS8wDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiEA4yQ/88ZrUX68c6kOe9G11u8NUaUzd8pLOtkKhniNOHoCIHmNX37JOqTcTzGn2u9+c8NlnvZ0uDvsd1BmKPaUmjmm-----END CERTIFICATE-----`
```

Certificate Verify

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.

data.json

```
{}
```

input.json

```
{}
```

```
package jwtresult.verify := io.jwt.verify_es256(es256_token, cert) # Verify the token with the certificateresult.payload := io.jwt.decode(es256_token)            # Decode the tokenresult.check := result.payload[1].iss == "xxx"          # Ensure the issuer (`iss`) claim is the expected value
```