---
schema_version: "1"
id: d6aff0006da03cf0499c870fd6e1c02bfb8307d251b27e6859cac80aabf6d887
title: Using JWT Library Functions
collection: mulesoft
version: current
locale: en-us
portal_url: https://docs.salesforce.com/mulesoft/current/en-us/pdk/1.9/policies-pdk-configure-features-jwt.md
canonical_url: https://docs.mulesoft.com/pdk/1.9/policies-pdk-configure-features-jwt
source_site: docs.mulesoft.com
content_type: documentation
content_hash: d30648d1af5cfc85fc3f25fc2064c6f9863b71cd92041d888155d1437e2cf76c
description: MuleSoft Documentation Site
release: "1.9"
latest: false
---
---
product: Omni Gateway Policy Development Kit (PDK)
version: 1.9
---

# Using JWT Library Functions

> For the full documentation index, see: https://docs.mulesoft.com/llms.txt

> [!NOTE] To view an example policy project that uses Omni Gateway Policy Development Kit (PDK)'s
> JWT library, see
> [JWT Validation Policy Example](https://github.com/mulesoft/pdk-custom-policy-examples/blob/1.9.0/jwt-validation/README.md).

JSON Web Token (JWT) is a URL-secure method of representing claims to be transferred between two
parties. The JWT token contains claims encoded in a JSON object as either the payload of a JSON Web
Signature (JWS) or as a JSON web encryption (JWE) structure in plain text, which enables the claims
to be digitally signed and protected with a message authentication code (MAC). Because the token is
signed, you can trust the information and its source.

PDK’s JWT library provides a set of tools to validate the JWT signatures and to extract and validate
the claims of all incoming requests.

> [!NOTE] The JWT library is gated behind a Cargo feature and is enabled by default. To disable JWT
> features for your policy, see
> [Configure PDK Features in Cargo.toml](https://docs.mulesoft.com/pdk/1.9/policies-pdk-create-project#configure-pdk-features).

## FIPS-Compliant JWT

PDK provides the `jwt-fips` feature for FIPS-compliant JWT support. This feature delegates
cryptography to the proxy-wasm host instead of bundling native RustCrypto. Because it’s mutually
exclusive with the default `jwt` backend, you must disable `default-features` when using it.

To enable FIPS-compliant JWT in your `Cargo.toml`:

```toml
# FIPS-compliant JWT only:
pdk = { version = "1.9.1", default-features = false, features = ["jwt-fips"] }

# FIPS-compliant JWT with XML Validator:
pdk = { version = "1.9.1", default-features = false, features = ["jwt-fips", "xml_validator"] }
```

## Extract a JWT Token

PDK provides a `TokenProvider` struct that has the `bearer` function to extract JWT tokens that have
the format `Bearer <token>` in the authorization header. The following code demonstrates how to use
the `bearer` function:

```Rust
// [...]
use pdk::jwt::*;
// [...]

async fn filter(
    state: RequestState,
) -> Flow<()> {
    let headers_state = state.into_headers_state().await;

    // Extract token
    let token = TokenProvider::bearer(headers_state.handler())?;
// [...]
```

If you are using a JWT token from a different source or with a different format, you can implement
Rust logic to get any other part of the request. Use a DataWeave parameter to configure extraction
to create a policy where you can dynamically change the JWT source.

## Validate a JWT Signature

The JWT library provides a helper for performing signature validation of the incoming requests
authorization tokens. Depending on the algorithm used by the policy, initialize a
`SignatureValidator` with the corresponding configuration:

```Rust
pub fn new(algorithm: SigningAlgorithm, key_length: SigningKeyLength, key: String) -> Result<SignatureValidator, JWTError>
```

PDK supports the following signing algorithms and key lengths:

<table><colgroup><col> <col></colgroup><tbody><tr><td><div><div><p>Signing Algorithm</p></div></div></td><td><div><div><p>Signing Key Length</p></div></div></td></tr><tr><td><div><div><p>RSA</p></div></div></td><td><div><div><p>256, 384 and 512</p></div></div></td></tr><tr><td><div><div><p>HMAC</p></div></div></td><td><div><div><p>256, 384 and 512</p></div></div></td></tr><tr><td><div><div><p>ES</p></div></div></td><td><div><div><p>256 and 384</p></div></div></td></tr></tbody></table>

The `SigningAlgorithm` enum defines the available signing algorithms:

```Rust
pub enum SigningAlgorithm {
    Rsa,
    Hmac,
    Es,
}
```

The `SigningKeyLength` enum defines the available signing key lengths:

```Rust
pub enum SigningKeyLength {
    Len256,
    Len384,
    Len512,
}
```

A `SignatureValidator` instance implements the `SignatureValidation` trait. This
`SignatureValidation` trait exposes a `validate` function that accepts tokens as `String` parameters
and returns a `Result` that contains the parsed `JWTClaims` or a `JWTError` in the event of an
error:

```Rust
pub trait SignatureValidation {
    fn validate(&self, token: String) -> Result<JWTClaims, JWTError>;
}
```

The following code example shows how to initialize the `SignatureValidator` and validate an incoming
token signed with a 256-byte HMAC algorithm:

```Rust
use anyhow::Result;
use pdk::hl::*;
use pdk::jwt::*;
// [...]

async fn filter(
    state: RequestState,
    signature_validator: &SignatureValidator,
) -> Flow<()> {
    let headers_state = state.into_headers_state().await;

    // Extract token
    let token = TokenProvider::bearer(headers_state.handler())?;

    if token.is_err() {
        return Flow::Break(Response::new(401).with_body("Bearer not found"));
    }

    // Validating signature
    let claims = signature_validator.validate(token.unwrap());

    if claims.is_err() {
        return Flow::Break(Response::new(401).with_body("Invalid token"));
    }
    // [...]
}

#[entrypoint]
async fn configure(launcher: Launcher, Configuration(configuration): Configuration) -> Result<()> {
    let config: Config = serde_json::from_slice(&configuration)?;

    let signature_validator = SignatureValidator::new(
        model::SigningAlgorithm::Hmac,
        model::SigningKeyLength::Len256,
        config.secret.clone(),
    )?;

    launcher
        .launch(on_request(|request| {
            filter(request, &signature_validator)
        }))
        .await?;
    Ok(())
}
```

Because, the `SignatureValidator` confirms that the policy configurations are correct during
initialization, initializing the `SignatureValidator` in the `#[entrypoint]` function throws an
early error when the policy is applied rather than when the API receives a request.

After initialization, the policy passes the `SignatureValidator` to the `on_request` wrapped
function to perform `validate` method on incoming requests.

## Create a JWT Token

> [!NOTE] For an example policy that generate JWT tokens, see
> [JWT Generation Example Policy](https://github.com/mulesoft/pdk-custom-policy-examples/blob/1.9.0/jwt-generation/README.md).

The JWT library provides a helper for creating JWT tokens. Initialize the `JwtGenerator` with your
signing algorithm configuration:

```Rust
pub fn new(
   algorithm: SigningAlgorithm,
   length: SigningKeyLength,
   key: &str,
) -> Result<Self, GeneratorError>
```

PDK supports these signing algorithms, key lengths, and PEM file formats. You must provide the `key`
as a PEM file:

<table><colgroup><col> <col> <col></colgroup><thead><tr><th>Signing Algorithm</th><th>Signing Key Length</th><th>PEM File Format</th></tr></thead><tbody><tr><td><div><div><p>RSA</p></div></div></td><td><div><div><p>256, 384, and 512</p></div></div></td><td><div><div><p>pkcs#8</p></div></div></td></tr><tr><td><div><div><p>HMAC</p></div></div></td><td><div><div><p>256, 384, and 512</p></div></div></td><td><div><div><p>Plain text</p></div></div></td></tr><tr><td><div><div><p>ES</p></div></div></td><td><div><div><p>256 and 384</p></div></div></td><td><div><div><p>pkcs#8</p></div></div></td></tr></tbody></table>

The JWT generator exposes the `jwt` function to create tokens with the given headers and claims
added to the JWT token:

```Rust
pub fn jwt(&self, claims: JWTClaims) -> Result<String, GeneratorError>
```

## Access Claims and Propagating to Headers

After the [signature validation](#signature-validation) executes, the result contains the parsed JWT
claims from the JWT token.

In case the signature is invalid or you choose not to validate the signature, PDK provides the
`JWTClaimsParser` to parse claims. This structure provides a `parse` method that returns
`Result<JWTClaims, JWTError>`.

```rust
// Being "token" a String that contains a JWT token
let parsed_claims = JWTClaimsParser::parse(token);

if claims.is_err() {
    return Flow::Break(Response::new(401).with_body("Invalid token"));
}
```

After you run the signature validation or the parsing method, use the following methods exposed by
the `JWTClaims` struct to access the JWT claims:

```rust
pub fn audience(&self) -> Option<Result<Vec<String>, JWTError>>

pub fn not_before(&self) -> Option<DateTime<Utc>>

pub fn expiration(&self) -> Option<DateTime<Utc>>

pub fn issued_at(&self) -> Option<DateTime<Utc>>

pub fn issuer(&self) -> Option<String>

pub fn jti(&self) -> Option<String>

pub fn nonce(&self) -> Option<String>

pub fn subject(&self) -> Option<String>

pub fn has_claim(&self, name: &str) -> bool

pub fn get_claim<T>(&self, name: &str) -> Option<T> where T: ValueRetrieval,

pub fn has_header(&self, name: &str) -> bool

pub fn get_header(&self, name: &str) -> Option<String>

pub fn get_claims(&self) -> pdk_script::Value

pub fn get_headers(&self) -> pdk_script::Value
```

The provided methods are designed to return each one of the standard JWT claims.

The `get_claim` method can return any standard or custom claim. Because `get_claim` supports
different target variable types, the user must specify the output type. `get_claim` supports
`String`, `f64`, `Vec<String>`, `chrono::DateTime<chono::Utc>`, and `serde_json::Value` output
types. Because the claim might not exist in the token, you must wrap the type with an `Option`, for
example:

```rust
let some_custom_claim: Option<String> = claims.get_claim("username");
```

The following example shows how to parse a JWT token, get a custom claim, and propagate it to the
request headers from a wrapped function:

```rust
async fn filter(
    state: RequestState,
) -> Flow<()> {

    let headers_state = state.into_headers_state().await;

    // Extract token
    let token = TokenProvider::bearer(headers_state.handler())?;

    if token.is_err() {
        return Flow::Break(Response::new(401).with_body("Bearer not found"));
    }

    // Being "token" a String that contains a JWT token
    let parsed_claims = JWTClaimsParser::parse(token.unwrap());

    if claims.is_err() {
        return Flow::Break(Response::new(401).with_body("Invalid token"));
    }

    let claims = claims.unwrap();

    let username: Option<String> = claims.get_claim("username");

    if let Some(custom_claim) = some_custom_claim {
        headers_state
            .handler()
            .set_header("username", custom_claim.as_str());
    }

    Flow::Continue(())
}
```

## Validate Claims

JWT tokens typically contain a set of standard and non-standard claims that you can validate. Use
the methods from [Access Claims and Propagating to Headers](#access-claims) to retrieve the claims
present in the JWT tokens’s header or payload. Once retrieved, validate the value of the claims.

The following code example validates that the JWT token:

- Is not expired by validating the `exp` claim.

- Has the correct audience value by validating the `aud` claim.

- Has the correct custom `role` claim by using a custom validator configured as a DataWeave
  expression policy parameter.

```Rust
use chrono::Utc;
use pdk::hl::*;
use pdk::jwt::*;
use pdk::logger::info;
use pdk::script::Evaluator;

async fn filter(
    state: RequestState,
    mut custom_validator: Evaluator<'_>,
) -> Flow<()> {
    let headers_state = state.into_headers_state().await;
    let token = TokenProvider::bearer(headers_state.handler());

    if token.is_err() {
        return Flow::Break(Response::new(400).with_body("Bearer not found"));
    }

    // Being "token" a String that contains a JWT token
    let parsed_claims = JWTClaimsParser::parse(token.unwrap());

    if claims.is_err() {
        return Flow::Break(Response::new(401).with_body("Invalid token"));
    }

    let claims = claims.unwrap();

    // Validating token expiration
    if let Some(exp) = claims.expiration() {
        if exp < Utc::now() {
            return Flow::Break(Response::new(400).with_body("token expired"));
        }
    } else {
        return Flow::Break(Response::new(400).with_body("token missing exp claim"));
    }

    // Validating audience
    if let Some(aud) = claims.audience() {
         if !aud_value.iter_mut().any(|a| a == "myAudience") {
            return Flow::Break(Response::new(400).with_body("token does not have the expected audience"));
        }
    }

    // Custom claim validation
    custom_validator.bind_vars("claimSet", claims.get_claims());
    let result = custom_validator_role_claim.eval();
    if !result.ok().and_then(|value| value.as_bool()).unwrap_or_default() {
        return Flow::Break(Response::new(400).with_body("custom token validations failed."));
    }

    Flow::Continue(())
}

#[entrypoint]
async fn configure(launcher: Launcher, Configuration(configuration): Configuration) -> Result<()> {
    let config: Config = serde_json::from_slice(&configuration)?;

    launcher
        .launch(on_request(|request| {
            filter(request, config.custom_validator_role.evaluator())
        }))
        .await?;
    Ok(())
}
```

In the above example, the custom `role` claim is defined by a DataWeave expression configured as an
input parameter in the `gcl.yaml` schema definition as follows:

```yaml
# [...]
spec:
  extends:
    - name: extension-definition
      namespace: default
  properties:
    customValidatorRole:
      type: string
      format: dataweave
      default: "#[vars.claimSet.role == 'superRole']"
      # [...]
  required:
    - customValidatorRole
```

## See Also

- [Implementing Your Custom Policy Features in Rust](https://docs.mulesoft.com/pdk/1.9/policies-pdk-configure-features)
