---
schema_version: "1"
id: 9936ba98b1b605e1d7730b0b8a27bea0db2907fb345ca579001cd84c4c39e8f8
title: Using Contracts Validation Library Functions
collection: mulesoft
version: current
locale: en-us
portal_url: https://docs.salesforce.com/mulesoft/current/en-us/pdk/1.3/policies-pdk-configure-features-contracts.md
canonical_url: https://docs.mulesoft.com/pdk/1.3/policies-pdk-configure-features-contracts
source_site: docs.mulesoft.com
content_type: documentation
content_hash: 610a1be3644647cc647f50cf3309b42f17af201084aab0c9a52ad1fbb252cf38
description: MuleSoft Documentation Site
release: "1.3"
latest: false
---
---
product: Omni Gateway Policy Development Kit (PDK)
version: 1.3
---

# Using Contracts Validation Library Functions

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

[Contracts](https://docs.mulesoft.com/api-manager/latest/api-contracts-landing-page) between API instances and
applications give the application access to the instance based on SLA tiers. Client applications can
validate their contracts by providing credentials that consist of the client ID and client secret.
The PDK Contracts Validation library provides functions to validate client credentials and implement
a custom client ID enforcement policy.

Only one contract at a time can exist between an API instance and an application.

## Extract Client Credentials

The Contracts Validation library is available from the `pdk::contracts` module.

The module provides the `ContractValidator` object to validate client credentials represented by the
`ClientId` and `ClientSecret` objects. Validate authentication and authorization credentials with
the `ContractValidator::authenticate()` and `ContractValidator::authorize()` methods:

```Rust
impl ContractValidator {
   pub fn authenticate(client_id: &ClientId, client_secret: &ClientSecret) -> Result<ClientData, AuthenticationError>;
   pub fn authorize(client_id: &ClientId, client_secret: &ClientSecret) -> Result<ClientData, AuthorizationError>;
}
```

Both methods return a `ClientData` struct that holds the client ID, client name, and SLA ID fields:

```Rust
pub struct ClientData {
    pub client_id: String,
    pub client_name: String,
    pub sla_id: Option<String>,
}
```

## Validate Request Authentication and Authorization Headers

Authenticate a request by extracting the client credentials from the request and then invoke the
`ClientValidation::authenticate()` method. The `pdk::contracts` module provides the
`basic_auth_credentials()` helper function to extract Basic Authentication credentials from request
headers:

```Rust
pub fn basic_auth_credentials(request_headers_state: &RequestHeadersState)
    -> Result<(ClientId, ClientSecret), BasicAuthError>;
```

This code snippet provides a simple authentication-request filter:

```Rust
async fn my_authentication_filter(
  state: RequestHeadersState,
  authentication: Authentication,
  validator: &ContractValidator,
) -> Flow<()> {

    // Extract credentials
    let (client_id, client_secret) = match basic_auth_credentials(&state) {
        Ok(credentials) => credentials,
        Err(e) => {
            logger::info!("Invalid credentials: {e}");

            // For simplicity, we are using a user-defined `unathorized_response()`
            // helper function for building responses.
            return Flow::Break(unauthorized_response("Invalid credentials", 401));
        }
    };

    // Validate authentication
    let validation = validator.authenticate(&client_id, &client_secret);

    let client_data = match validation {
        Ok(client_data) => client_data,
        Err(e) => {
            logger::info!("Invalid authentication: {e}");
            return Flow::Break(unauthorized_response("Invalid authentication", 403));
        }
    };

    // Update the current authentication
    if let Some(mut auth) = authentication.authentication() {
        auth.client_id = Some(client_data.client_id);
        auth.client_name = Some(client_data.client_name);

        authentication.set_authentication(Some(&auth));
    }

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

This code snippet provides a simple authorization-request filter:

```Rust
async fn my_authorization_filter(
  state: RequestHeadersState,
  validator: &ContractValidator,
) -> Flow<()> {

    // Extract client id with a user defined helper `extract_client_id()` function,
    let client_id = match extract_client_id(&state) {
        Ok(credentials) => credentials,
        Err(e) => {
            logger::info!("Invalid credentials: {e}");

            // For simplicity, we are using a user-defined `unathorized_response()`
            // helper function for building responses.
            return Flow::Break(unauthorized_response("Invalid credentials", 401));
        }
    };

    // Validate authorization
    let validation = validator.authorize(&client_id);

    if let  Err(e) = validation {
        logger::info!("Invalid authentication: {e}");
        return Flow::Break(unauthorized_response("Invalid authentication", 403));
    }

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

## Implement Custom Extraction for Client Credentials

Invoke the `ClientId::new()` and `ClientSecret::new()` methods to extract credentials:

```Rust
impl ClientId {
   pub fn new(client_id: String) -> Self;
}

impl ClientSecret {
   pub fn new(client_secret: String) -> Self;
}
```

After extracting the credentials, initialize a set of the credentials:

```Rust
fn initialize_credentials(raw_client_id: String, raw_client_secret) -> (ClientId, ClientSecret) {
   let client_id = ClientId::new(raw_client_id);
   let client_secret = ClientSecret::new(raw_client_secret);

   (client_id, client_secret)
}
```

> [!NOTE] For security, the content of `ClientSecret` is deleted after use, and the `Debug` trait
> doesn’t reveal the `ClientSecret` content.

## Inject the ContractValidator Object

Inject the `ContractValidator` object into the `#[entrypoint]` function and share its reference to
the request filter:

```Rust
#[entrypoint]
async fn configure(launcher: Launcher, validator: ContractValidator) -> Result<(), LaunchError> {

    let filter = on_request(|state, authentication| my_authentication_filter(state, authentication, &validator));
    launcher.launch(filter).await?;

    OK(())
}
```

### Poll the Local Contracts Database

The `ContractValidator` object maintains a local copy of the contracts database. You must poll the
local copy periodically to maintain a valid copy of the contracts. Invoke the
`ContractValidator::update_contracts()` method to poll the local copy:

```Rust
impl ContractValidator {
    pub async fn update_contracts(&self) -> Result<(), UpdateError>;
}
```

If the `ContractValidator::update_contracts()` method returns an error that specifies a connectivity
problem occurred during the contracts database polling, you must implement the retry and error
handling heuristics. To do this, invoke `ContractValidator::update_contracts()` in a period
specified by the `ContractValidator::UPDATE_PERIOD` constant:

```Rust
async fn update_my_contracts(validator: &ContractValidator, clock: Clock) {

    // Configure a new timer
    let timer = clock.period(ContractValidator::UPDATE_PERIOD);

    loop {
       // Update result handling should be customized by the programmer
       let update_result = validator.update_contracts().await;

       // Wait for the next tick
       if !timer.next_tick().await {
           // If no more ticks are available, finish the task.
           return;
       }
    }
}
```

The contract database initialization period specifies when to poll the contracts database at a
higher frequency than update period. The `ContractValidator::INITIALIZATION_PERIOD` specifies the
interval required by the initial polling:

```Rust
async fn initialize_my_contracts(validator: &ContractValidator, clock: Clock) {

    // Configure a new timer
    let timer = clock.period(ContractValidator::UPDATE_PERIOD);

    loop {
       // Update result handling should be customized by the programmer
       let update_result = validator.update_contracts().await;

       // Wait for the next tick
       if !timer.next_tick().await {
           // If no more ticks are available, finish the task.
           return;
       }
    }
}
```

This snippet shows a complete contract polling task with initialization and update polling periods:

```Rust
async fn update_my_contracts(validator: &ContractValidator, clock: Clock) {
    let initialization_timer = clock.period(ContractValidator::INITIALIZATION_PERIOD);

    loop {
        if validator.update_contracts().await.is_ok() {
            logger::info!("Contracts storage initialized.");
            break;
        }

        if !initialization_timer.next_tick().await {
            logger::info!("Tick event suspended.");
            break;
        }
 }

    let update_timer = initialization_timer
        .release()
        .period(ContractValidator::UPDATE_PERIOD);

   loop {
        let _ = validator.update_contracts().await;

        if !update_timer.next_tick().await {
            logger::info!("Tick event suspended.");
            break;
        }
        logger::info!("Retrying contracts storage initialization.");
    }
}
```

Because the contracts database polling task must run concurrently with the `Launcher::launch()`
task, use the `join!()` macro from the [futures](https://crates.io/crates/futures) crate to join
both tasks. This snippet implements a complete `#[entrypoint]` function with polling and launching:

```Rust
#[entrypoint]
async fn configure(launcher: Launcher, clock: Clock,validator: ContractValidator) -> Result<(), LauncherError> {

    let filter = on_request(|state, authentication| my_authentication_filter(state, authentication, &validator));

    let (_, launcher_result) = join! {
        update_my_contracts(&validator, clock),
        launcher.launch(filter),
    };

    launcher_result
}
```

## See Also

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

- [Configuring Delayed, Periodic, and Synchronous Functions](https://docs.mulesoft.com/pdk/1.3/policies-pdk-configure-features-timer)

- [Client Applications, Contracts, and Credentials](https://docs.mulesoft.com/api-manager/latest/api-contracts-landing-page)
