---
title: Common bindings
description: Each script type exposes a number of bindings, objects that Advanced Identity Cloud injects into the script execution context. The bindings provide a stable way of accessing Advanced Identity Cloud functionality, without the need to allowlist Java classes. Scripts are provided with all the bindings for their context at the point of execution.
component: pingoneaic
page_id: pingoneaic:am-scripting:script-bindings
canonical_url: https://docs.pingidentity.com/pingoneaic/am-scripting/script-bindings.html
keywords: ["Scripts", "ESVs"]
section_ids:
  common-cookiename: Retrieve cookie name
  common-httpclient: Access HTTP services
  methods: Methods
  httpclient-sync-get: "Example: Send a synchronous request (GET)"
  httpclient-sync: "Example: Send a synchronous request (POST)"
  httpclient-async: "Example: Send an asynchronous request"
  httpclient-basic: "Example: Send a request using basic authentication"
  httpclient-mtls: "Example: Send a request using mTLS and set timeouts"
  httpclient-mtls-config-service: Configure the HTTP Client service
  httpclient-mtls-map-secret: Map a base64-encoded PEM certificate to the secret label
  httpclient-mtls-create-script: Create a script to send the HTTP request
  httpclient-proxy: "Example: Route a request through a proxy"
  httpclient-proxy-service: Configure the HTTP Client service
  httpclient-proxy-map-secret: Map a secret to the secret label
  httpclient-proxy-create-script: Create a script to send the HTTP request
  jwt-support: Generate and validate JWTs
  common-locales: Get localized messages
  method: Method
  example: Example
  common-logger: Log script messages
  common-journey: Get journey details
  methods_2: Methods
  example_2: Example
  common-openidm: Access IDM scripting functions
  common-realm: Output realm name
  common-scriptName: Output script name
  common-systemenv: Reference ESVs in scripts
  common-utils: Access utility functions
  common-policy: Evaluate policies
  methods_3: Methods
  example_3: Example
---

# Common bindings

Each [script type](scripting-api.html) exposes a number of *bindings*, objects that Advanced Identity Cloud injects into the script execution context. The bindings provide a stable way of accessing Advanced Identity Cloud functionality, without the need to allowlist Java classes. Scripts are provided with all the bindings for their context at the point of execution.

Find information about context-specific bindings in the documentation for each script type.

|   |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| - | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | Advanced Identity Cloud has introduced a [next-generation scripting engine](next-generation-scripts.html) that offers several benefits, including enhanced script bindings.The availability and usage of bindings depend on the script engine version of the script: legacy or next-generation. Both versions are described in this section.You can find information about migrating to the enhanced scripting engine in [Migrate to next-generation scripts](next-generation-scripts.html#migrate-to-v2-steps). |

The following bindings are common to many authentication and authorization scripts. Use these bindings to access data and perform script operations such as logging.

|                   |                                                                                                                    |                  |                     |
| ----------------- | ------------------------------------------------------------------------------------------------------------------ | ---------------- | ------------------- |
| **Binding**       | **Description**                                                                                                    | **Availability** |                     |
|                   |                                                                                                                    | **Legacy**       | **Next-generation** |
| `cookieName`      | Access the name of the current cookie.                                                                             | No               | Yes                 |
| `httpClient`      | Make outbound HTTP calls, including asynchronous requests and requests using mTLS.                                 | Partial 1        | Yes                 |
| `jwtAssertion`(1) | Generate JWT assertions in scripts.                                                                                | No               | Yes                 |
| `jwtValidator`(1) | Validate JWT assertions in scripts.                                                                                | No               | Yes                 |
| `locales`         | Get a localized message.                                                                                           | No               | Partial 2           |
| `logger`          | Write a message to the Advanced Identity Cloud debug log.                                                          | Yes              | Yes                 |
| `journey`         | Identify the current journey and get information about the journey and its configuration.                          | No               | Partial 2           |
| `openidm`         | Manage an IDM resource.                                                                                            | No               | Yes                 |
| `policy`          | Evaluate policies using the policy engine API.                                                                     | No               | Yes                 |
| `realm`           | Access the realm to which the user is authenticating.                                                              | Yes              | Yes                 |
| `scriptName`      | Access the name of the running script.                                                                             | Partial 1        | Yes                 |
| `systemEnv`       | Reference system properties.                                                                                       | Yes              | Yes                 |
| `utils`           | Access utility functions such as base64 encoding/decoding, cryptographic operations, and generating random values. | No               | Yes                 |

1 Available in OAuth 2.0, Scripted Decision node, and SAML 2.0 scripts.

2 Available in Configuration Provider node, Scripted Decison node, Device Match node, and custom node scripts.

|   |                                                                                                                                                                                                                                                                                                                                                                                          |
| - | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | Make sure you don't use the same name for a local variable as that of a common binding in your script. These names are reserved for common bindings only.If you have already defined a local variable with the same name as one that's added to common bindings in a more recent version of Advanced Identity Cloud; for example, `utils`, you must rename the variable in your scripts. |

## Retrieve cookie name

The `cookieName` binding lets you access the name of the cookie as a string. You can use the cookie name to perform session actions such as ending all open sessions for a user.

* Next-generation

* Legacy

```javascript
// add cookie name to shared state, for example: 8a92ca506c38f08
nodeState.putShared("myCookie", cookieName);
```

*Not available in Legacy bindings*

## Access HTTP services

Call HTTP services with the `httpClient.send` method. HTTP client requests are asynchronous, unless you invoke the `get()` method on the returned object.

### Methods

* Next-generation

* Legacy

The `httpClient` binding uses native JavaScript objects to send requests and receive responses, in a similar way to the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API).

**To invoke an HTTP request:**

* `ResponseScriptWrapper httpClient.send(String uri, Map requestOptions).get()`

  Sends a synchronous request to the specified URI with request options. The `requestOptions` parameter is a native JavaScript object that supports `method`, `headers`, `form`, `clientName`, `token`, and `body` as attributes.

  The `requestOptions` parameter is a native JavaScript object that supports these attributes:

  | Field        | Type                                                                                                                                                                                                                                                                                                                                   |
  | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | `method`     | The HTTP request method. For example, `GET`, `POST`, `PUT`, `DELETE`, `HEAD`.                                                                                                                                                                                                                                                          |
  | `headers`    | The request headers. For example, `"Content-Type": "application/json"`.                                                                                                                                                                                                                                                                |
  | `form`       | Required for sending a form request.The `form` attribute automatically url-encodes fields, so you don't need to specify `"Content-Type": "application/x-www-form-urlencoded"` as part of the headers.For example:```javascript
  var requestOptions = {
    method: "POST",
    form: {
      field1: "value1",
      field2: "value2"
    }
  }
  ``` |
  | `clientName` | The HTTP client instance required for [sending a request using MTLS](#httpclient-mtls).                                                                                                                                                                                                                                                |
  | `token`      | The token specified as the Authorization header, for example, when [sending a synchronous request](#httpclient-sync).                                                                                                                                                                                                                  |
  | `body`       | The content of the request. Not specified for `GET`, `HEAD`, or `TRACE` methods.                                                                                                                                                                                                                                                       |

* `ResponseScriptWrapper httpClient.send(String uri).get()`

  Sends a synchronous GET request with no additional request options.

**To access response data:**

* `Map response.formData()`

* `Map response.json()`

* `String response.text()`

  The following fields provide response status information:

  | Field        | Type    |
  | ------------ | ------- |
  | `headers`    | Map     |
  | `ok`         | boolean |
  | `status`     | integer |
  | `statusText` | String  |

  The response is similar to [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) object behavior.

To invoke a synchronous HTTP request:

* `HTTPClientResponse httpClient.send(Request request).get()`

  To access response data:

* `JSON.parse(response.getEntity().getString())`

`HttpClientResponse` methods:

* `Map<String, String> getCookies()`

* `String getEntity`

* `Map<String, String> getHeaders()`

* `String getReasonPhrase()`

* `Integer getStatusCode()`

* `Boolean hasCookies`

* `Boolean hasHeaders`

|   |                                                                                                                                                                                                                                                                                                    |
| - | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | The `httpClient` script binding automatically adds the current transaction ID as an HTTP header, `X-ForgeRock-TransactionId`. This lets you correlate caller and receiver logs when you use `httpClient` from your script to make requests to other Advanced Identity Cloud products and services. |

The following examples demonstrate different ways to send HTTP client requests:

* [Example: Send a synchronous request (GET)](#httpclient-sync-get)

* [Example: Send a synchronous request (POST)](#httpclient-sync)

* [Example: Send an asynchronous request](#httpclient-async)

* [Example: Send a request using basic authentication](#httpclient-basic)

* [Example: Send a request using mTLS and set timeouts](#httpclient-mtls)

### Example: Send a synchronous request (GET)

The following example uses the `httpClient` binding in a next-generation script to make a GET request to generate random UUIDs.

```javascript
var BASE_URL = "http://www.randomnumberapi.com/api/v1.0/uuid";

var COUNT = 5;

var options = {
  method: "GET",
  headers: {
    "Content-Type": "application/json; charset=UTF-8"
  }
};
var requestURL = `${BASE_URL}?count=${COUNT}`;

var response = httpClient.send(requestURL, options).get();

if (response.status === 200) {
  var uuids = JSON.parse(response.text());
  nodeState.putShared("UUIDs", uuids);
  action.goTo("true");
} else {
  logger.error("Error generating UUIDs: " + response.statusText);
  action.goTo("false");
}
```

Use a [Debug node](https://docs.pingidentity.com/auth-node-ref/latest/am-only/debug.html) to verify the UUIDs stored in `nodeState`. For example:

```json
{
    ...
    "UUIDs": [
        "d787a51e-7b2a-4eba-9d87-7ec555ec9f32",
        "f561381a-ec03-4b48-8d6d-828c80d43805",
        "6d9ef759-be3d-414d-a942-dce8d3840b59",
        "40737769-0c91-41e9-a0c4-7deab4a15aea",
        "5a40bdb6-62d3-406f-bd23-71be1d5a54f5"
    ]
}
```

### Example: Send a synchronous request (POST)

The following example uses the `httpClient` binding to send a synchronous authentication request and check for success.

* Next-generation

* Legacy

This example assumes you've created a custom library script (`authLib`) that handles authentication.

```javascript
var bearerToken = "Bearer abcd-1234";

var requestOptions = {
  method: "POST",
  headers: {
    "Content-Type": "application/json"
  },
  token: bearerToken, // Equivalent to Authorization header
  body: {
    username: "bjensen"
  }
}

var requestURL = "https://my.auth.server/authenticate";
var response = httpClient.send(requestURL, requestOptions).get();

if (response.status === 200) {
    action.goTo("true");
} else {
    action.goTo("false");
}
```

```javascript
var fr = JavaImporter(org.forgerock.openam.auth.node.api.Action);

var requestURL = "https://my.auth.server/authenticate";
var request = new org.forgerock.http.protocol.Request();
request.setUri(requestURL);
request.setMethod("POST");
request.getHeaders().add("Content-Type", "application/json;");
request.getHeaders().add("Authorization", "Bearer abcd-1234");
request.setEntity(JSON.stringify({"username": "bjensen"}));

var response = httpClient.send(request).get();

var responseCode = response.getStatus().getCode();
if (responseCode === 200) {
    action = fr.Action.goTo("true").build();
} else {
    action = fr.Action.goTo("false").build();
}
```

### Example: Send an asynchronous request

The `httpclient` binding also supports asynchronous requests so that you can perform non-blocking operations, such as recording logging output after the script has completed.

To make an asynchronous request, use the same method signatures to send the request but without calling `get()` on the returned object. The `send()` method then initiates a separate thread to handle the response. Callers are unable to control when the asynchronous call is processed, so won't be able to use the response as part of authentication processing.

* Next-generation

* Legacy

```javascript
public Promise<ResponseScriptWrapper, HttpClientScriptException> send(String uri)
public Promise<ResponseScriptWrapper, HttpClientScriptException> send(String uri, Map<String, Object> requestOptions)
```

```javascript
public Promise<Response, NeverThrowsException> send(Request request)
```

For example:

* Next-generation

* Legacy

```javascript
var requestURL = "https://my.auth.server/audit";
// creates separate thread to handle response
var response = httpClient.send(requestURL).then((response) => {
  if (!response) {
    logger.error("Bad response from " + requestURL);
    return;
  }
  if (response.status != 200) {
    logger.error("Unexpected response: " + response.statusText);
    return;
  }
  logger.debug("Returned from async request");
});
// continues processing whilst awaiting response
action.goTo("true");
```

```javascript
var fr = JavaImporter(
    org.forgerock.http.protocol.Request,
    org.forgerock.http.protocol.Response,
    org.forgerock.openam.auth.node.api.Action);

var request = new fr.Request();
request.setUri("https://my.auth.server/audit");
request.setMethod("GET");

var response = httpClient.send(request).then((response) => {
  if (!response) {
    logger.error("Bad response from " + requestURL);
    return;
  }
  var status = response.getStatus().getCode();

  if (status != 200) {
    logger.error("Unexpected response: " + response.getEntity().getString());
    return;
  }
  logger.message("Returned from async request");
});

action = fr.Action.goTo("true").build();
```

### Example: Send a request using basic authentication

The following script uses the encoded username and password in a basic authentication header to access the [http://httpbin.org/basic-auth/{user}/{passwd}](http://httpbin.org/#/Auth/get_basic_auth__user__passwd_) service.

* Next-generation

* Legacy

```javascript
// password stored as an ESV
var password = systemEnv.getProperty('esv.my.password');

var auth = utils.base64.encode("bjensen:" + password);

var requestURL = "http://httpbin.org/basic-auth/bjensen/passwd";

var requestOptions = {
  method: "GET",
  headers: {
    "Content-Type": "application/json",
    "Authorization": "Basic ".concat(auth)
  },
}
var response = httpClient.send(requestURL, requestOptions).get();

if (!response) {
  logger.error("Bad response from " + requestURL);
  action.goTo("false");
} else {
  if (response.status != 200) {
    logger.warn("Authentication not successful. Code: " + response.status);
    action.goTo("false");
  } else {
    logger.debug("Authenticated: " + response.json().authenticated);
    action.goTo("true");
  }
}
```

|   |                                                                                                                                   |
| - | --------------------------------------------------------------------------------------------------------------------------------- |
|   | To construct the header for basic authorization, make sure you use the `concat()` function rather than `+` to append credentials. |

|   |                                                                                                                                                                                                                                                                                                                                                     |
| - | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | To use this sample script, add the following classes to the class allowlist property in the `AUTHENTICATION_TREE_DECISION_NODE` scripting engine configuration:- `org.mozilla.javascript.ConsString`

- `java.util.Base64`

- `java.util.Base64$Encoder`For details, refer to [Access Java classes](scripting-env.html#scripting-env-java-classes). |

```javascript
var fr = JavaImporter(org.forgerock.openam.auth.node.api.Action);

// password stored as an ESV
var password = systemEnv.getProperty('esv.my.password');

var auth = java.util.Base64.getEncoder().encodeToString(java.lang.String("bjensen:" + password).getBytes());

var request = new org.forgerock.http.protocol.Request();
request.setMethod("GET");
request.setUri("http://httpbin.org/basic-auth/bjensen/passwd");
request.getHeaders().add("content-type","application/json; charset=utf-8");
request.getHeaders().add("Authorization", "Basic " + auth);

var response = httpClient.send(request).get();
var jsonResult = JSON.parse(response.getEntity().getString());
logger.message("Script result: " + JSON.stringify(jsonResult));

if (jsonResult.hasOwnProperty("authenticated")) {
  action = fr.Action.goTo("success").build();
} else {
  action = fr.Action.goTo("failure").build();
}
```

### Example: Send a request using mTLS and set timeouts

Configure the `httpclient` to use mTLS to exchange data securely when making an HTTP request to an external service.

Follow these example steps to send an HTTP request using mTLS:

1. [Configure an instance of the HTTP Client service](#httpclient-mtls-config-service)

2. [Map a client certificate to a secret label](#httpclient-mtls-map-secret)

3. [Create a script to send the request](#httpclient-mtls-create-script)

#### Configure the HTTP Client service

Complete these steps to configure an instance of the HTTP Client service.

The instance defines settings such as timeout values and the client certificate or truststore secret labels required by the `httpclient` script binding to make a TLS connection. You can configure the instance to override default values.

For example, to set connection or response timeout values for a request initiated by the HTTP client, enable `Use Instance Timeouts` in the service instance and set the timeout accordingly.

You can find information about these settings in the [Http Client service configuration](../am-reference/services-configuration.html#realm-httpclient).

1. In the AM native admin console, go to Realms > *Realm Name* > Services.

2. Click Add a Service and select Http Client Service from the service type drop-down list.

3. Enable the service and save your changes.

4. On the Secondary Configurations tab, click Add a Secondary Configuration.

5. Provide a name for the HTTP client instance, for example, `myHttpClient`. Then click Create.

6. Enable the instance and save your changes.

7. On the TLS Configuration tab, enter an identifier to be used in your [secret label](../am-reference/secret-id-mappings.html#httpclient-secret-labels) in the Client Certificate Secret Label Identifier field.

   For example, `testCrt` creates the dynamic secret label, `am.services.httpclient.mtls.clientcert.testCrt.secret`.

   |   |                                                                                                                                                                                                                                                          |
   | - | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
   |   | To specify a truststore to verify the target server's certificate, provide a value for Server Trust Certificates Secret Label Identifier.This creates the dynamic secret label, `am.services.httpclient.mtls.servertrustcerts.[.var]_identifier.secret`. |

8. Save your changes.

#### Map a base64-encoded PEM certificate to the secret label

|   |                                                                                                                                                                              |
| - | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | To prepare a certificate for TLS connections, it must be:- **Base64-encoded**

- **A file containing both a private and public key**

- **Uploaded as an ESV using the API** |

Complete these example steps to generate a key pair and map the secret to the dynamic secret label created in the previous step.

1. Generate a private key and a public key, as described in [Generate an RSA key pair](../tenants/esvs-signing-encryption.html#generate-an-rsa-key-pair).

   |   |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
   | - | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
   |   | To use a client certificate issued by a certificate authority (CA), concatenate the certificates in the order required by [RFC 4346](https://www.rfc-editor.org/rfc/rfc4346.html#section-7.4.2):1) The client certificate (`client.crt`)

   2) Any intermediate CA certificates

   3) The root CA certificate (`ca.crt`)Then append the private key:```bash
   cat client.crt ca.crt client.key > myfile.pem
   ```Verify the resulting PEM file is valid, for example:```bash
   openssl x509 -in myfile.pem -noout -text
   ``` |

   You should now have a `.pem` file that contains a base64-encoded key pair. Advanced Identity Cloud shares the public key and uses the private key to sign the request.

2. [Get an access token](../developer-docs/authenticate-to-rest-api-with-access-token.html#get-an-access-token) for the realm.

3. Specify the access token in a REST API call to create a PEM-encoded ESV secret.

   For example, to create a secret named `esv-mtls-cert`:

   ```none
   $ curl \
   --request PUT 'https://<tenant-env-fqdn>/environment/secrets/<esv-mtls-cert>' \
   --header 'Authorization: Bearer <access-token>' \
   --header 'Content-Type: application/json' \
   --header 'Accept-API-Version: protocol=1.0;resource=1.0' \
   --data-raw '{
       "encoding": "pem",
       "useInPlaceholders": false,
       "valueBase64": "<base64-encoded PEM-file>"
   }'
   ```

   |   |                                                                                                  |
   | - | ------------------------------------------------------------------------------------------------ |
   |   | You must specify the encoding type as `pem` for the API to recognize the value as a certificate. |

4. [Map the secret](../tenants/esvs-signing-encryption.html#map-esv-secrets-to-secret-labels) against the secret label created when you configured the [HTTP Client service](#httpclient-mtls-config-service), for example:

   * Secret Label

     `am.services.httpclient.mtls.clientcert.testCrt.secret`

   * alias

     `esv-mtls-cert`

   The certificate is now uploaded and mapped to the secret label.

#### Create a script to send the HTTP request

Write a [next-generation decision node script](../developer-docs/scripting-auth.html#create-decision-scripts) to send a request using the HTTP client instance in the request options.

1. In your script, specify your HTTP client instance as the value for `clientName` in `requestOptions`.

   For example:

   ```javascript
    var requestOptions = {
       "clientName": "myhttpclient"   (1)
    }
   var res = httpClient.send("https://example.com",
                                       requestOptions).get(); (2)
   action.withHeader(`Response code: ${res.status}`);

   if (res.status == 200) {
     action.goTo("true").withDescription(response.text());
   } else {
     action.goTo("false");
   };
   ```

   |       |                                                                                           |
   | ----- | ----------------------------------------------------------------------------------------- |
   | **1** | The `clientName` attribute must reference an enabled instance of the HTTP Client service. |
   | **2** | The HTTP client sends the request to an mTLS endpoint that checks for a certificate.      |

2. Create a simple journey that includes the scripted decision node to test your changes.

3. Verify that the HTTP request is sent successfully.

### Example: Route a request through a proxy

Follow these example steps to send an external HTTP request by connecting to a proxy server:

1. [Configure an instance of the HTTP Client service](#httpclient-proxy-service)

2. [Map a secret to a secret label](#httpclient-proxy-map-secret)

3. [Create a script to send the request](#httpclient-proxy-create-script)

#### Configure the HTTP Client service

Configure an instance of the HTTP Client service to override the system proxy connection. This lets you use specific proxy settings per request.

This example configures a proxy connection with authentication, but this is optional.

1. In the AM native admin console, go to Realms > *Realm Name* > Services.

2. Click Add a Service and select Http Client Service from the list of service types.

3. Enable the service and save your changes.

4. On the Secondary Configurations tab, click Add a Secondary Configuration.

5. Provide a name for the HTTP client instance; for example, `myHttpClient`, and click Create.

6. Enable the configuration and save your changes.

   Make sure both the service *and* the secondary configuration are enabled.

7. On the Proxy Configuration tab, enable Use Instance Proxy, and enter values for the following fields:

   * Proxy URI

     The proxy server URI, for example: `https://proxyexample.com:8888`.

   * Proxy Username

     The username to use for proxy authentication, for example: `admin`.

   * Proxy Secret Label Identifier

     The identifier for the secret label mapping to use for proxy authentication, for example: `myProxy`.

     This creates the secret label `am.services.httpclient.proxy.myProxy.secret`.

   You can find information about these settings in the [Http Client proxy configuration](../am-reference/services-configuration.html#httpclient-secondary-config-proxy).

8. Save your changes.

#### Map a secret to the secret label

To enable proxy authentication, follow the steps described in [Map ESV secrets to secret labels](../tenants/esvs-signing-encryption.html#map-esv-secrets-to-secret-labels) to reference the dynamic label generated from the proxy configuration.

1. Create an ESV with the value of the secret to use for proxy authentication.

   For example, `esv-httpclient-proxy-secret`.

2. Add a mapping. For example, if you set the proxy secret label identifier to `myProxy`, map:

   * Secret Label

     `am.services.httpclient.proxy.myProxy.secret`

   * Alias

     `esv-httpclient-proxy-secret`.

#### Create a script to send the HTTP request

Write a [next-generation decision node script](next-generation-scripts.html) to send a request using the HTTP client instance in the request options.

1. In your script, specify the name of your HTTP client instance as the value for `clientName` in `requestOptions`.

   For example:

   ```javascript
   var requestOptions = {
     "clientName": "myHttpClient"
   }
   var res = httpClient.send("https://example.com",
                             requestOptions).get();
   logger.info(`Status code: ${res.status}`);

   if (res.status == 200) {
     action.goTo("true");
   } else {
     logger.error(res.text());
     action.goTo("false");
   };
   ```

2. Create a simple journey that includes the Scripted Decision node to test your changes.

3. Verify that the HTTP request is sent successfully using the configured proxy connection.

### Generate and validate JWTs

Use the `jwtAssertion` and `jwtValidator` bindings to include JSON Web Token (JWT) operations in your script.

The `jwtAssertion` binding lets you generate signed and/or encrypted JWTs. For example, generate a JWT assertion to transport claims securely and verify them later in the journey through an emailed magic link. JWTs are signed using the HS256 or RS256 algorithms.

The `jwtValidator` binding lets you decrypt and validate JWTs. For example, use the binding to verify JWT claims generated in a previous node or from another system, such as PingGateway.

* `String jwtAssertion.generateJwt(Map<String, Object> jwtData)`

  Provide the following data to generate a JWT assertion:

  | Data field        | Description                                                                                                                                                                                                                                                    |
  | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | `jwtType`         | (*Required*)The type of JWT to generate, one of:- `SIGNED`

  - `SIGNED_THEN_ENCRYPTED`

  - `ENCRYPTED_THEN_SIGNED`Encrypted options are only supported for HS256 JWTs.                                                                                           |
  | `jwsAlgorithm`    | (*Required*) `HS256` or `RS256` (`jwtType` must be `SIGNED`).                                                                                                                                                                                                  |
  | `issuer`          | The JWT issuer (`iss`) claim. You must provide a value for either `issuer` or `stableId` at a minimum.                                                                                                                                                         |
  | `audience`        | The JWT audience (`aud`) claim.                                                                                                                                                                                                                                |
  | `subject`         | The JWT subject (`sub`) claim.                                                                                                                                                                                                                                 |
  | `type`            | The JWT type (`typ`) claim, typically `JWT`.                                                                                                                                                                                                                   |
  | `jwtId`           | Specify a value for the JWT ID (`jti`).                                                                                                                                                                                                                        |
  | `claims`          | Custom claims in the format `"key":"value"`.                                                                                                                                                                                                                   |
  | `stableId`        | Stable ID. You must provide a value for either `issuer` or `stableId` at a minimum.                                                                                                                                                                            |
  | `accountId`       | *Deprecated*. To support backwards compatibility, the account ID (if specified) is set as the `issuer`, `stableId` and `subject` when these values aren't provided.                                                                                            |
  | `validityMinutes` | The duration of the validity of the JWT in minutes.                                                                                                                                                                                                            |
  | `privateKey`      | The RSA private key in JSON Web Key (JWK) [format](https://www.rfc-editor.org/rfc/rfc7518#section-6.3). For example, generate your own private key with <https://www.openssl.org>.Required for `RS256`-signed JWTs.                                            |
  | `signingKey`      | The base64-encoded [JSON Web Key](https://www.rfc-editor.org/rfc/rfc7517.html) used to sign/verify the JWT.Required for `HS256`-signed JWTS.                                                                                                                   |
  | `encryptionKey`   | The [JSON Web Encryption (JWE)](https://www.rfc-editor.org/rfc/rfc7516.html) public key used to encrypt/decrypt the JWT. JWTs are encrypted using the A128CBC-HS256 algorithm.*Generation of RS256-encrypted signed JWT assertions isn't currently supported*. |

  * Next-generation

  * Legacy

  **JWT generation example 1: HS256 encrypted then signed:**

  ```javascript
  var hmacJwtData = {
    jwtType: "ENCRYPTED_THEN_SIGNED",
    jwsAlgorithm: "HS256",
    issuer: "issuer",
    subject: "subject",
    audience: "https://<tenant-env-fqdn>/am/oauth2/access_token",
    type: "JWT",
    validityMinutes: 10,
    claims: {
      "key1": "value1",
      "key2": "value2"
    },
    signingKey: "cGFzc3dvcmQ=",
    encryptionKey: "Syz1K5XQCZtq7FkE+GNvgZPeFyvUXJdemIW7CQjM18U="
  };
  // returns a string representation of the JWT
  var assertionJwt = jwtAssertion.generateJwt(hmacJwtData);

  if (assertionJwt !== null && assertionJwt.length > 0) {
    logger.debug("AssertionJwt: " + assertionJwt);
    // store JWT in nodeState for validation later in journey
    nodeState.putShared("assertionJwt" , assertionJwt);
    action.goTo("true");
  } else {
    action.goTo("false");
  }
  ```

  **JWT generation example 2: RS256 signed:**

  ```javascript
  var rsaJwtData = {
    jwtType: "SIGNED",
    jwsAlgorithm: "RS256",
    accountId: "accountId",
    audience: "https://<tenant-env-fqdn>/am/oauth2/access_token",
    validityMinutes: 10,
    privateKey: {
      "p": "0BRJ6TrTpeT3XM1aXj9ZiTDfVTD0Aqufhm0a2Cm7Zr3ObqkBbZrm2KH9BY23nfY_TFbd6kx31YHqjpoV4KeThn2uvZ7gPw_ILljk5WQwgFq_gdDvAq3Iw4MlwGoR51nSaGGqKU6Dt2PvVOB4I3azVJr1f9Vsm47L6Llp8YjKtBE",
      "kty": "RSA",
      "q": "ugtiWmODuy3XuWGf3u5hvF4RglZZK5IPYRkJjSz8j90DxYVPD_CBNJx8j_FGUJ6BBNRTs2yylgMJdcFs-WxcFR7iQD2OzgzSdeRgrh34RmLjAXEq-X0OF9P3lqnBXIx-uVL3-rG8jQWSzc016o3PWjclOKqLx7oBmYs7w6WbJLE",
      "d": "c2DR3SOQkzu6f5eRLFLURphQCbrN4JCAlOo2S_D07UJmMiYtIFpOezbLazQYXdebiV-pPv-zZcOWHhOr3HMgYLu8JBN29mrJS8kDIWMjCx8vMJgrNLfBZO4az—​t_Kyow4p0n3HdaYRu0K4lqskXe68Syl0XAlHfnd7q-bB-UUGB89j3E-FfXIIjKktn_koBc8hX2DhUnJgduFi9CcAQVO9wSjjfyB6ksn01_YaMt5MHsHKhqDvZeCdEHfwyFer8vvDRCTru_msl_fu_MqQi15igTJu6f7eBsVQQLnb7L1fQ0BURck7oVMjTvyYz_nRbnMkKSrWpa-j1d1Z4TTucAQ",
      "e": "AQAB",
      "use": "sig",
      "kid": "iUE-em7bU5j1yJN6hEMKx6ZmtWBYGZycCuO94X1sssE",
      "qi": "rUqLFjJ2L3FNrj65tdUCusQ-_7g1rKsTOGnQUrVcgYSsHb3aYR90zV651MiL0X4gp6mzgc8QcSdzc1KbEmR5VHm5IH4N6f9yBNb2yO_8sftmS8PiRjZjVLUORnwmouJ4cPsob0RPx9mwGLIURLxQDstE4UQ0j6iMWF74iezwxO8",
      "dp": "f60DURXkijV9RrdGjPAIK3MOhoJ8JytRvjUyNJMex0MN6L7Q_oT-wsxaqc60bTuMyXW_wyVanmqSFyAa7ndEwVBbKUTUSj2P0kh_YvXgANIuEiS2k4k42CafwnoTNEbcIWpT8_aWQbATSZxWe0Q5c1-F5gN6GdU77zfd9vO9lVE",
      "alg": "RS256",
      "dq": "A8RdPnVLYovgFVnbsdjj07uX4Sq8bXxsoUuvfNNPXd5cyDAV1L3K7_THNObuxI0hEab29ugZiZ4QH_lFqps-FhNlA2X7sUJjNI3mQ0BKGarA6_ONqjWVBnh9R-iyCJyzqC785G-a4MQfH9mq4M_0ReBd-ZLCd83VYHWIRULiLFE",
      "n": "lzf-g94TfT9JeQ7kRZCkSOKwP0rtpe2IzX6C42NN1EE4hejwCjIAj4oUHrcNyrcVZ6hIu3a5r09fnzp5w9RS6ooMkp-AQ_9C5T8hFbf61J4lT3kmIp-jv50MF7oJCGOidLPCiJ-3EsnBKFjomRcCQa_r-sHF9hfORvhypBcj_U1OMMRM28yX7JVggG7f_YPlmx03c7meKPE-4xXnfdFDxbjbntlWSul6qm0YOTRVfuZHubwu-HOZEDB4dKkA3-0qAev6FULW7tNOqoMj5KLlejeiuCOQeAMTqPnBqOdH8iC4u6WHArsRqkmOdLgVs0uLlVPz9796qIKlosP5EMPjwQ"
    }
  };

  var assertionJwt = jwtAssertion.generateJwt(rsaJwtData);

  if (assertionJwt !== null && assertionJwt.length > 0) {
    logger.debug("AssertionJwt: " + assertionJwt);
    // store JWT in nodeState for validation later in journey
    nodeState.putShared("assertionJwt" , assertionJwt);
    action.goTo("true");
  } else {
    action.goTo("false");
  }
  ```

  *Not available in Legacy bindings*

* `Map<String, Object> jwtValidator.validateJwtClaims(Map<String, Object> jwtData)`

  Provide values for the following supported fields to validate the specified JWT assertion:

  | Data field      | Description                                                                                                                                                                                                                                                   |
  | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | `jwtType`       | (*Required*) The type of JWT to validate: `SIGNED`, `SIGNED_THEN_ENCRYPTED`, or `ENCRYPTED_THEN_SIGNED`.                                                                                                                                                      |
  | `jwt`           | (*Required*) The JWT object to validate.                                                                                                                                                                                                                      |
  | `issuer`        | The JWT issuer (`iss`) claim. You must provide a value for either `issuer` or `stableId` at a minimum.                                                                                                                                                        |
  | `audience`      | The JWT audience (`aud`) claim value.                                                                                                                                                                                                                         |
  | `subject`       | The JWT subject (`sub`) claim.                                                                                                                                                                                                                                |
  | `type`          | The JWT type (`typ`) claim.                                                                                                                                                                                                                                   |
  | `claims`        | Custom claims in the format `"key":"value"`.                                                                                                                                                                                                                  |
  | `stableId`      | Stable ID. You must provide a value for either `issuer` or `stableId` at a minimum.                                                                                                                                                                           |
  | `accountId`     | *Deprecated*. To support backwards compatibility, the account ID (if specified) is used to validate the `issuer`, `stableId` and `subject` when these values aren't provided.                                                                                 |
  | `signingKey`    | The base64-encoded [JSON Web Key](https://www.rfc-editor.org/rfc/rfc7517.html) used to sign/verify the JWT.JWTS are signed using the HS256 or RS256 algorithms.                                                                                               |
  | `encryptionKey` | The [JSON Web Encryption (JWE)](https://www.rfc-editor.org/rfc/rfc7516.html) public key used to encrypt/decrypt the JWT.JWTs are encrypted using the A128CBC-HS256 algorithm.*Validation of RS256-encrypted signed JWT assertions isn't currently supported*. |

  * Next-generation

  * Legacy

  **JWT validation example 1: HS256 encrypted then signed:**

  ```javascript
  var jwtData = {
    jwtType: "ENCRYPTED_THEN_SIGNED",
    issuer: "issuer",
    subject: "subject",
    audience: "https://<tenant-env-fqdn>/am/oauth2/access_token",
    type: "JWT",
    signingKey: "cGFzc3dvcmQ=",
    encryptionKey: "Syz1K5XQCZtq7FkE+GNvgZPeFyvUXJdemIW7CQjM18U="
  };
  // get JWT from nodeState (JWT generation example 1)
  var assertionJwt = nodeState.get("assertionJwt");

  if (assertionJwt !== null && assertionJwt.length > 0) {
    jwtData["jwt"] = assertionJwt;

    try {
      // returns a map of JWT claims or null if required claims are missing
      // throws NoSuchSecretException if verification key is missing
      var jwtClaims = jwtValidator.validateJwtClaims(jwtData);
      if (jwtClaims !== null) {
        // retrieve and log some JWT claim values
        logger.debug("Audience: " + jwtClaims.get("audience"));
        logger.debug("Subject: " + jwtClaims.get("subject"));
        logger.debug("Expiration Time: " + jwtClaims.get("expirationTime"));
        logger.debug("Issued At: " + jwtClaims.get("issuedAt"));
        logger.debug("JWT ID: " + jwtClaims.get("jwtId"));
        logger.debug("key1: " + jwtClaims.get("key1")); // custom claim
        action.goTo("true");
      } else {
        logger.error("Invalid JWT claims");
        action.goTo("false");
      }
    } catch(e) {
      logger.error("Invalid JWT signing key");
      action.goTo("false");
    }
  } else {
    logger.error("Error getting assertionJwt");
    action.goTo("false");
  }
  ```

  **JWT validation example 2: RS256 signed:**

  ```javascript
  var jwtData = {
    jwtType: "SIGNED",
    accountId: "accountId",
    audience: "https://<tenant-env-fqdn>/am/oauth2/access_token",
    signingKey: "cGFzc3dvcmQ="
  };
  // get JWT from nodeState (JWT generation example 2)
  var assertionJwt = nodeState.get("assertionJwt");

  if (assertionJwt !== null && assertionJwt.length > 0) {
    jwtData["jwt"] = assertionJwt;

    try {
      // returns a map of JWT claims or null if required claims are missing
      // throws NoSuchSecretException if verification key is missing
      var jwtClaims = jwtValidator.validateJwtClaims(jwtData);
      if (jwtClaims !== null) {
        // retrieve and log JWT claim values
        logger.debug("Audience: " + jwtClaims.get("audience"));
        action.goTo("true");
      } else {
        logger.error("Invalid JWT claims");
        action.goTo("false");
      }
    } catch(e) {
      logger.error("Invalid JWT signing key");
      action.goTo("false");
    }
  } else {
    logger.error("Error getting assertionJwt");
    action.goTo("false");
  }
  ```

  *Not available in Legacy bindings*

## Get localized messages

Use the next-generation `locales` binding to return the localized version of a string from a translation map.

The binding includes a method that determines the best locale based on the `Accept-Language` HTTP header or default system settings, in a similar way to the [Message node](https://docs.pingidentity.com/auth-node-ref/latest/message.html).

If no match is found, the method returns the first entry in the map.

### Method

`String getLocalizedMessage(Map<String, String> localizations)`

### Example

The following example sets the `greeting` property to `Hello` for a United States English locale. For *British* English settings, the greeting is set to the first entry in the map, `Gutentag`, because no match is found.

```javascript
var languageMap =
{
  'de': 'Gutentag',
  'no': 'Hei',
  'fr': 'Bonjour',
  'en-US': 'Hello'
};

var greeting = locales.getLocalizedMessage(languageMap);
```

## Log script messages

Write messages to Advanced Identity Cloud debug logs by using the `logger` object.

Scripts that create debug messages have their own logger which is created after the script has executed at least once.

Logger names use the format: ``scripts.<context>.<script UUID>.(<script name>); for example, `scripts.OIDC_CLAIMS.36863ffb-40ec-48b9-94b1-9a99f71cc3b5.(OIDC Claims Script)``.

You can find information about debug logs in [Get audit and debug logs](../tenants/audit-debug-logs.html).

* Next-generation

* Legacy

The `ScriptedLoggerWrapper` is based on the [SLF4J](https://www.slf4j.org) logging framework. You can log messages at the following levels:

* Trace

* Debug (*default level for development tenant environments*)

* Info

* Warn (*default level for staging and production environments*)

* Error

```javascript
var traceEnabled = logger.isTraceEnabled();
logger.trace("Trace with arg {}", arg);
var debugEnabled = logger.isDebugEnabled();
logger.debug("Debug with arg {}", arg);
var infoEnabled = logger.isInfoEnabled();
logger.info("Info with arg {}", arg);
var warnEnabled = logger.isWarnEnabled();
logger.warn("Warn with arg {}", arg);
var errorEnabled = logger.isErrorEnabled();
logger.error("Error with arg {}", arg);
```

The `Debug` logger lets you log messages at the following levels:

* Message

* Warning

* Error

```javascript
var messageEnabled = logger.messageEnabled();
logger.message("Message with arg {}", arg);
var warnEnabled = logger.warningEnabled();
logger.warning("Warn with arg {}", arg);
var errorEnabled = logger.errorEnabled();
logger.error("Error with arg {}", arg);
```

## Get journey details

The next-generation `journey` binding provides information about the current journey.

Call the following methods to access details about the journey and how it's configured.

### Methods

* String name()

  Returns the name of the current journey. This can be an inner or an outer journey.

* String identityResource()

  Returns the identity resource of the current journey. For example, `managed/alpha_user`.

* boolean innerJourney()

  Returns true if the current journey is [configured to run as an inner journey only](../am-authentication/auth-nodes-and-journeys.html#disable-child-journey).

* boolean mustRun()

  Returns true if the current journey is [set to always run](../am-authentication/auth-nodes-and-journeys.html#authn-mustrun-tree) regardless of whether the user authenticated successfully and a session exists or not.

### Example

* Next-generation

* Legacy

```javascript
var currentJourney = journey.name();

logger.info(currentJourney + " identity resource: " + journey.identityResource());

if (journey.innerJourney()){
  logger.info(currentJourney + " is an inner journey.");
}
if(journey.mustRun()){
  logger.info(currentJourney + " is a mustRun journey.");
}
```

*Not available in Legacy bindings*

## Access IDM scripting functions

The `openidm` binding lets you manage an IDM resource by calling scripting functions directly from a next-generation script.

The following CRUDPAQ functions are supported:

* create

* read

* update

* delete

* patch

* action

* query

For more information, refer to [Scripting functions](../idm-scripting/scripting-func-engine.html).

|   |                                                                                                                                       |
| - | ------------------------------------------------------------------------------------------------------------------------------------- |
|   | The `openidm` binding provides administrative access to IDM functions. Use it with caution to prevent the exposure of sensitive data. |

The following example illustrates how to create a user, update their details, send an email, and finally delete the user:

* Next-generation

* Legacy

```javascript
var username = "bjensen";

// CREATE: returns the user identity as a JSON object (wrapped in a MapScriptWrapper)
var newUser = openidm.create("managed/alpha_user", null, {
  "userName": username,
  "mail": "bjensen@example.com",
  "givenName": "Barbara",
  "sn": "Jensen"});

// Access the fields directly, for example: ._id, .sn, .city, .country
var userID = newUser._id;

// READ: returns entire identity as a JSON object
var user = openidm.read("managed/alpha_user/" + userID);

// Debug to output all fields
logger.debug("user: " + JSON.stringify(user));

// UPDATE: replaces entire identity with specified object
// Returns the updated identity as a JSON object
user.description = 'New description';
var updatedUser = openidm.update("managed/alpha_user/" + userID, null, user);

// PATCH: selectively modify object, returns entire identity
var patchedUser = openidm.patch("managed/alpha_user/" + userID, null, [{
        "operation":"replace",
        "field":"/mail",
        "value":"new@example.com"
}]);

// QUERY: returns results array in a map
var queryRes = openidm.query("managed/alpha_user",
    {"_queryFilter":`/userName eq '${username}'`},["*", "_id"]);

// Debug query result count and the requested properties
logger.debug("Query result count: " + queryRes.resultCount);
logger.debug("Queried user: " + queryRes.result[0].givenName);

// ACTION: send email using the action function
var actionRes = openidm.action("external/email", "send", {
    "from": "admin@example.com",
    "to": patchedUser.mail,
    "subject": "Example email",
    "body": "This is an example"
});
// Example response if not null: {"status":"OK","message":"Email sent"}
logger.debug("Status: " + actionRes.status + " : " + actionRes.message);

// DELETE: returns deleted object if successful, throws exception if not
openidm.delete('managed/alpha_user/'+ userID, null);

action.goTo("true");
```

*Not available in Legacy bindings*

## Output realm name

The `realm` binding lets you access the name of the realm to which the user is authenticating as a string.

For example, authenticating to the `alpha` realm returns a string value of `/alpha`.

* Next-generation

* Legacy

```javascript
// log current realm
logger.debug("User authentication realm: " + realm);
```

```javascript
// log current realm
logger.message("User authentication realm: " + realm);
```

## Output script name

Use the `scriptName` binding to get the name of the running script as a string.

* Next-generation

* Legacy

```javascript
// log current script name
logger.debug("Running script: " + scriptName);

// or use a library script to log script name
var mylib = require('loggingLibrary');
mylib.debug(logger, scriptName);
```

```javascript
// log current script name
logger.message("Running script: " + scriptName);
```

## Reference ESVs in scripts

The `systemEnv` binding, available to all script types, provides the following methods shown with their Java signatures:

```java
String getProperty(String propertyName);
String getProperty(String propertyName, String defaultValue);
<T> T getProperty(String propertyName, String defaultValue, Class<T> returnType);
```

where:

* `propertyName` refers to an ESV *(tooltip: environment secrets and variables)*. For details, refer to [ESVs](../tenants/esvs.html).

  The `propertyName` always starts with `esv.`; for example, `esv.my.variable`.

  Make sure the `propertyName` is specific enough to distinguish it from all other ESVs defined.

* `defaultValue` is a default value to use when no ESV matches `propertyName`.

  The `defaultValue` must not be `null`.

* `returnType` is one of the following fully-qualified Java class names:

  * `java.lang.Boolean`

  * `java.lang.Double`

  * `java.lang.Integer`

  * `java.lang.String`

  * `java.util.List`

  * `java.util.Map`

The `getProperty(String propertyName)` method returns `null` when the `propertyName` is not valid.

For example:

```javascript
var myProperty = systemEnv.getProperty('esv.my.variable');
var myDefault = systemEnv.getProperty('esv.nonexisting.variable', 'defaultValue');
var myDouble = systemEnv.getProperty('esv.double.variable', '0.5', java.lang.Double);
var myBool = systemEnv.getProperty('esv.bool.variable', false, java.lang.Boolean);
var myInt = systemEnv.getProperty('esv.int.variable', 34, java.lang.Integer);
var map = systemEnv.getProperty('esv.map.variable', '{"defaultKey":"defaultValue"}', java.util.Map);
```

## Access utility functions

Use the next-generation `utils` binding to perform functions such as encoding/decoding and encryption/decryption, type conversion, and cryptographic operations.

|   |                                                        |
| - | ------------------------------------------------------ |
|   | The `utils` binding isn't available in legacy scripts. |

> **Collapse: Base64 encode and decode**
>
> * String base64.encode(String toEncode)
>
>   Encodes the specified text using base64.
>
> * String base64.encode(byte\[] toEncode)
>
>   Encodes the specified bytes using base64.
>
> * String base64.decode(String toDecode)
>
>   Decodes the specified text using base64.
>
> * byte\[] base64.decodeToBytes(String toDecode)
>
>   Decodes the specified text using base64 and returns the result as an array of bytes.
>
> * Example
>
> ```javascript
> var txt = "exampletext";
> var bytes = utils.types.stringToBytes(txt);
>
> var encoded = utils.base64.encode(txt);
> logger.debug("Encoded text: " + encoded); //ZXhhbXBsZXRleHQ=
>
> var decoded = utils.base64.decode(encoded);
> logger.debug("Decoded text: " + decoded);
>
>
> var encodedBytes = utils.base64.encode(bytes);
> logger.debug("Encoded bytes: " + encodedBytes);
>
> var decodedBytes = utils.base64.decode(encodedBytes);
> logger.debug("Decoded bytes: " + decodedBytes);
> ```

> **Collapse: Base64Url encode and decode**
>
> * String base64url.encode(String toEncode)
>
>   Encodes the specified text using base64url.
>
> * String base64url.encode(byte\[] toEncode)
>
>   Encodes the specified bytes using base64url.
>
> * String base64url.decode(String toDecode)
>
>   Decodes the specified text using base64url.
>
> * byte\[] base64url.decodeToBytes(String toDecode)
>
>   Decodes the specified text using base64url and returns the result as an array of bytes.
>
> * Example
>
> ```javascript
> var url = "http://exampletext=";
> var bytesUrl = utils.types.stringToBytes(url);
>
> var encodedURL = utils.base64url.encode(url);
> logger.debug("Encoded URL: " + encodedURL); //aHR0cDovL2V4YW1wbGV0ZXh0PQ
>
> var decodedURL = utils.base64url.decode(encodedURL);
> logger.debug("Decoded URL: " + decodedURL);
>
> var encodedBytesUrl = utils.base64url.encode(bytesUrl);
> logger.debug("Encoded bytes: " + encodedBytesUrl);
>
> var decodedBytesUrl = utils.base64url.decode(encodedBytesUrl);
> logger.debug("Decoded bytes: " + decodedBytesUrl);
> ```

> **Collapse: Generate random values**
>
> * String crypto.randomUUID()
>
>   Returns a type 4 pseudo-random generated UUID.
>
> * \<JavaScript array> crypto.getRandomValues(\<JavaScript array> array)
>
>   Returns the specified array filled with the same number of generated random numbers.
>
> * Example
>
> ```javascript
> // generate a pseudorandom UUID (version 4)
> var uuid = utils.crypto.randomUUID();
> logger.debug("UUID: " + uuid); //eef5b4e1-ae86-4c0a-9160-5afee2b5e791
>
> // generate an array of 5 random values
> var array = [0,0,0,0,0];
> utils.crypto.getRandomValues(array);
> array.forEach(function(element){
>   logger.debug("Random value: " + element);
> });
> ```

> **Collapse: Convert types**
>
> * String types.bytesToString(byte\[] toConvert)
>
>   Converts a byte array to a string.
>
> * byte\[] types.stringToBytes(String toConvert)
>
>   Converts a string to a byte array.
>
> * Example
>
> ```javascript
> var dataBytes = utils.types.stringToBytes("data");
> var dataString = utils.types.bytesToString(dataBytes);
> ```

> **Collapse: Generate keys**
>
> * Object crypto.subtle.generateKey(String algorithm)
>
>   Generates a key using the specified algorithm and default values.
>
> * Object crypto.subtle.generateKey(Map\<String, Object> algorithm)
>
>   Generates a key using the parameters provided, depending on the algorithm specified.
>
> * Parameters
>
> | Option          | Algorithm | Description                                                                            |
> | --------------- | --------- | -------------------------------------------------------------------------------------- |
> | `name`          | All       | *Required*. The name of the algorithm. Possible values: `AES`, `RSA`, `HMAC`, `ECDSA`. |
> | `length`        | `AES`     | *Optional*. Default: `256`.                                                            |
> | `modulusLength` | `RSA`     | *Optional*. Default: `2048`.                                                           |
> | `namedCurve`    | `ECDSA`   | *Optional*. Possible values: `P-256` (default), `P-384`, `P-521`.                      |
> | `hash`          | `HMAC`    | *Optional*. Possible values: `SHA-1`, `SHA-256` (default), `SHA-384`, `SHA-512`.       |
>
> * Example
>
> ```javascript
> var aesKey = utils.crypto.subtle.generateKey("AES");
>
> // Optionally specify 'length' (default 256)
> var aesKeyCustom = utils.crypto.subtle.generateKey(
>   {
>     "name": "AES", length: 256
>   }
> );
>
> var rsaKey = utils.crypto.subtle.generateKey("RSA");
>
> // Optionally specify 'modulusLength' (default 2048)
> var rsaKeyCustom = utils.crypto.subtle.generateKey(
>   {
>     "name": "RSA", modulusLength: 4096
>   }
> );
>
> var hmacKey = utils.crypto.subtle.generateKey("HMAC");
>
> // Optionally specify 'hash' (default 'SHA-256')
> var hmacKeyCustom = utils.crypto.subtle.generateKey(
>   {
>     "name": "HMAC", "hash": "SHA-384"
>   }
> );
>
> var ecdsaKey = utils.crypto.subtle.generateKey("ECDSA");
>
> // Optionally specify 'namedCurve' (default P-256)
> var ecdsaKeyCustom = utils.crypto.subtle.generateKey(
>   {
>     "name": "ECDSA", namedCurve: "P-384"
>   }
> );
>
> logger.debug("AES key: " + aesKey.length);
> logger.debug("HMAC key: " + hmacKey.length);
> logger.debug("ECDSA key: " + ecdsaKey.publicKey.length + " : " + ecdsaKey.privateKey.length);
> logger.debug("RSA keys: " + rsaKey.publicKey.length + " : " + rsaKey.privateKey.length);
> ```

> **Collapse: Derive keys**
>
> * byte\[] crypto.subtle.deriveKey(String algorithm, byte\[] baseKey, Number derivedKeyLength)
>
>   Derives a key to the specified length, using the algorithm details and the base key provided.
>
>   This method supports the [PBKDF2](https://www.rfc-editor.org/rfc/rfc2898.html#appendix-A.2) key derivation function, which enhances key security by repeatedly applying a cryptographic function to a base key and salt. The more iterations, the more secure the key becomes.
>
> * Example
>
> ```javascript
> // get salt as byte[] - for example, from nodeState or API
> var salt = utils.types.stringToBytes("random-salt");
>
> // get key as byte[] - for example, from nodeState or secret store
> var baseKey = systemEnv.getProperty('esv.my.password');
>
> // length in octets, for example 128, 256, 512
> var derivedKeyLength = 256;
>
> // derivation algorithm must be PBKDF2
> // hash can be SHA-1, SHA-256, SHA-384, SHA-512
> var algorithmParams = {
> "name": "PBKDF2",
> "hash": "SHA-256",
> "salt": salt,
> "iterations": 10
> }
>
> var key = utils.crypto.subtle.deriveKey(algorithmParams, baseKey, derivedKeyLength);
>
> // verify that length is 32 (256 bits)
> logger.debug("Derived key length: " + key.length);
> ```

> **Collapse: Encrypt and decrypt**
>
> * byte\[] crypto.subtle.encrypt(String algorithm, byte\[] key, byte\[] data)
>
>   Encrypts the data using the specified key and algorithm (`AES` or `RSA`).
>
> * byte\[] crypto.subtle.decrypt(String algorithm, byte\[] key, byte\[] data)
>
>   Decrypts the data using the specified key and algorithm (`AES` or `RSA`).
>
> * Example
>
> ```javascript
> var data = utils.types.stringToBytes("data");
>
> var aesKey = utils.crypto.subtle.generateKey("AES");
> var rsaKey = utils.crypto.subtle.generateKey("RSA");
>
> var encryptedAes = utils.crypto.subtle.encrypt("AES", aesKey, data);
> var decryptedAes = utils.crypto.subtle.decrypt("AES", aesKey, encryptedAes);
>
> var encryptedRsa = utils.crypto.subtle.encrypt("RSA", rsaKey.publicKey, data);
> var decryptedRsa = utils.crypto.subtle.decrypt("RSA", rsaKey.privateKey, encryptedRsa);
>
> logger.debug("decryptedAes: " + decryptedAes + " decryptedRsa: " + decryptedRsa);
> ```

> **Collapse: Compute digest (hash) values**
>
> * String crypto.subtle.digest(String algorithm, byte\[] data)
>
>   Returns the digest of the data using the specified algorithm. The algorithm must be one of `SHA-1`, `SHA-256`, `SHA-384`, `SHA-512`.
>
> * Example
>
> ```javascript
> var data = utils.types.stringToBytes("data");
> var digest = utils.crypto.subtle.digest("SHA-256", data);
>
> logger.debug("Digest length: " + digest.length);
> ```

> **Collapse: Sign and verify**
>
> * byte\[] sign(String algorithm, byte\[] key, byte\[] data)
>
>   Signs the data using the specified algorithm and key.
>
> * byte\[] sign(Map\<String, Object> algorithmOptions, byte\[] key, byte\[] data)
>
>   Signs the data using the specified algorithm options and key.
>
> * boolean verify(String algorithm, byte\[] key, byte\[] data, byte\[] signature)
>
>   Verifies the signature of the data using the specified algorithm and key.
>
> * boolean verify(Map\<String, Object> algorithmOptions, byte\[] key, byte\[] data, byte\[] signature)
>
>   Verifies the signature of the data using the specified key and map of parameters.
>
> * Parameters
>
> | Option | Algorithm       | Description                                                                                          |
> | ------ | --------------- | ---------------------------------------------------------------------------------------------------- |
> | `name` | All             | *Required*. The name of the algorithm. Possible values: `RSA`, `HMAC`, `ECDSA`.                      |
> | `hash` | `HMAC`, `ECDSA` | *Optional*. Possible values: `SHA-1` (**HMAC only**), `SHA-256` (default), `SHA-384`, `SHA-512` (1). |
>
> (1) The `namedCurve` length must match the `hash` length for EDCSA keys. For example, `P-256` and `SHA-256`, or `P-521` and `SHA-512`.
>
> * Example
>
> ```javascript
> var data = utils.types.stringToBytes("data");
> var rsaKey = utils.crypto.subtle.generateKey("RSA");
> var hmacKey = utils.crypto.subtle.generateKey("HMAC");
> var ecdsaKey = utils.crypto.subtle.generateKey("ECDSA");
>
> var signRsa = utils.crypto.subtle.sign("RSA", rsaKey.privateKey, data);
> var verifyRsa = utils.crypto.subtle.verify("RSA", rsaKey.publicKey, data, signRsa);
>
> var hmacOpts = {
>   "name": "HMAC",
>   "hash": "SHA-512"
> }
> var signHmac = utils.crypto.subtle.sign(hmacOpts, hmacKey, data);
> var verifyHmac = utils.crypto.subtle.verify(hmacOpts, hmacKey, data, signHmac);
>
> var ecdsaOpts = {
>   "name": "ECDSA",
>   "hash": "SHA-256"
> }
>
> var signEcdsa = utils.crypto.subtle.sign(ecdsaOpts, ecdsaKey.privateKey, data);
> var verifyEcdsa = utils.crypto.subtle.verify(ecdsaOpts, ecdsaKey.publicKey, data, signEcdsa);
>
> logger.debug("RSA key verified: " + verifyRsa);
> logger.debug("HMAC key verified: " + verifyHmac);
> logger.debug("ECDSA key verified: " + verifyEcdsa);
> ```

## Evaluate policies

The next-generation `policy` binding lets you access the policy engine API and evaluate policies from within scripts.

### Methods

* List\<Map\<String, Object>> policy.evaluate(subject, application, resources, environment)

  Use the `evaluate()` method to request policy decisions for specific resources.

* Parameters

  The following parameters are required:

  | Parameter     | Type                        | Description                                                                                   |
  | ------------- | --------------------------- | --------------------------------------------------------------------------------------------- |
  | `subject`     | Map\<String, Object>        | The subject making the request, specified as an `ssoToken`, a `jwt`, or a `claims` value.     |
  | `application` | String                      | The name of the policy set.                                                                   |
  | `resources`   | List\<String>               | The resources to request decisions for.                                                       |
  | `environment` | Map\<String, List\<String>> | Specify environment conditions as a map of keys to lists of values, or `{}` to indicate none. |

* Returns

  The method returns evaluation decisions as a list of maps containing the following fields:

  | Field        | Description                                                                                                                                                                                                              |
  | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
  | `resource`   | The requested resource.                                                                                                                                                                                                  |
  | `actions`    | A map of actions and corresponding boolean values. For example:```json
  "actions":{
      "POST":false,
      "PATCH":false,
      "GET":false,
      "DELETE":false,
      "OPTIONS":true,
      "HEAD":false,
      "PUT":false
  }
  ``` |
  | `attributes` | A map of attribute names to their values if attributes exist for the policy.                                                                                                                                             |
  | `advices`    | A map of advice names to their values if advice exists for the policy.                                                                                                                                                   |

Learn how the `evaluate` method works and its parameters in [Request policy decisions for a specific resource](../am-authorization/rest-api-authz-policy-decisions.html#rest-api-authz-policy-decision-concrete). The `policy` binding works in a similar way to this REST API call.

### Example

The following example script requests a policy decision for a URL resource.

```javascript
// Set the subject to the ssoToken of an authenticated user
var subject = {
    ssoToken: requestCookies[cookieName]
}
var application = "testPolicySet"

var resources = ["http://example.com:80/test"]

var environment = {
    "myField": ["myValue"]
}

var evaluationResult;
try {
    // policy.evaluate() returns List<Map<String, Object>>
    var results = policy.evaluate(subject, application, resources, environment);
    evaluationResult = results[0];
} catch(e) {
    logger.error(`Policy Evaluation Failed: ${e.message}`)
}

if (evaluationResult && evaluationResult.actions['GET'] === true) {
    action.goTo("authorized")
} else {
    action.goTo("unauthorized")
}
```
