---
title: Next-generation scripts
description: The next-generation scripting engine offers the following benefits:
component: pingam
version: 7.4
page_id: pingam:am-scripting:next-generation-scripts
canonical_url: https://docs.pingidentity.com/pingam/8.1/am-scripting/next-generation-scripts.html
llms_txt: https://docs.pingidentity.com/pingam/llms.txt
docs_for_agents: https://developer.pingidentity.com/build-with-ai/docs-for-agents.md
page_aliases: ["scripting-guide:next-generation-scripts.adoc"]
superseded_by: https://docs.pingidentity.com/pingam/8.1/am-scripting/next-generation-scripts.html
section_ids:
  migrate-to-v2-steps: Migrate to next-generation scripts
  v2-action: action
  v2-callbacksBuilder: callbacksBuilder
  v2-httpClient: httpClient
  v2-idRepository: idRepository
  v2-logger: logger
  v2-nodeState: nodeState
  v2-openidm: openidm
  error-handling: Exception handling when using next-generation script bindings
  general_exception_handling: General exception handling
  exception_handling_within_a_promise: Exception handling within a Promise
---

# Next-generation scripts

The next-generation scripting engine offers the following benefits:

* Stability

  * A stable set of enhanced bindings, available to JavaScript decision node scripts, that reduces the need to allowlist Java classes to access common functionality.

* Ease of use

  * Simplify your scripts with fewer imports and more intuitive return types that require less code.

  * Debug more easily with clear log messages and a simple logging interface based on SLF4J.

  * Make requests to other APIs from within scripts more easily with a more intuitive HTTP client.

* Reduced complexity

  * Simplify and modularize your scripts with [library scripts](library-scripts.html) by reusing commonly used code snippets as CommonJS modules.

    Reference library scripts from a decision node script.

  * Access identity management information seamlessly through the `openidm` binding.

## Migrate to next-generation scripts

Different bindings are available to the decision node script depending on the scripting engine version; legacy or next-generation.

|   |                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| - | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | The next-generation engine can't use legacy scripts or scripts written in Groovy.If your [Scripted Decision node](https://docs.pingidentity.com/auth-node-ref/7.4/scripted-decision.html) uses legacy scripts, you must convert them to use updated bindings to take advantage of the benefits of the next-generation scripting engine.Where possible, you should migrate legacy scripts to take advantage of next-generation stability. |

You can't change the script engine version after you have created a script.

To migrate existing scripts, create a new script and convert your legacy code:

1. [Create a decision node script](manage-scripts-console.html#create-scripts-with-console) (type: `Decision node script for authentication trees`) and select Next Generation on the Choose Script Engine page.

2. Copy and paste the legacy version of your script into the JavaScript field.

3. Review any Java classes that you needed to allowlist to use in your legacy script.

   *You can't add Java classes to the next-generation allowlist*.

   Instead, check if any next-generation bindings provide similar functionality, or reimplement the class as a [library script](library-scripts.html). Library scripts let you add third-party code as reusable JavaScript modules that can be referenced from other scripts.

   If this isn't possible, you can [request](https://support.pingidentity.com/s/article/Raising-an-RFE) the functionality to be included as a supported script binding in a future release.

4. Review the changes in the following table and update the bindings according to the examples in the links provided.

   | Binding            | Next-generation change                                                                                                                                                                                                                                                  | Example                                                               |
   | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
   | `action`           | **New**.Use static method `goTo()` to set the script outcome.To send callbacks, instead of calling `Action.send()`, use the new `callbacksBuilder` functionality.                                                                                                       | [`action`](#v2-action) and [`callbacksBuilder`](#v2-callbacksBuilder) |
   | `callbacksBuilder` | **New**.Instead of creating a `Callback` object and invoking `Action.send()`, add callbacks using static methods on the `callbacksBuilder` object; for example `nameCallback` and `passwordCallback`. These callbacks are automatically sent when the script completes. | [`callbacksBuilder`](#v2-callbacksBuilder)                            |
   | `httpClient`       | Uses native JavaScript objects, similar to the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API).                                                                                                                                                 | [`httpClient`](#v2-httpClient)                                        |
   | `idRepository`     | Class changed from `ScriptIdentityRepository` to `ScriptedIdentityRepository`.Use `getIdentity()` method in addition to methods to get or set attributes.&#xA;&#xA;You must now explicitly call store() to persist changes to attribute values.                         | [`idRepository`](#v2-idRepository)                                    |
   | `jwtAssertion`     | **New**.Generate JWT assertions in scripts.                                                                                                                                                                                                                             | [Generate and validate JWTs](scripting-api-node.html#jwt-support)     |
   | `jwtValidator`     | **New**.Validate JWT assertions in scripts.                                                                                                                                                                                                                             | [Generate and validate JWTs](scripting-api-node.html#jwt-support)     |
   | `logger`           | Logger is now based on `org.slf4j.Logger`, instead of `com.sun.identity.shared.debug.Debug`.                                                                                                                                                                            | [`logger`](#v2-logger)                                                |
   | `nodeState`        | The `sharedState` and `transientState` bindings are no longer supported.                                                                                                                                                                                                | [`nodeState`](#v2-nodeState)                                          |
   | `openidm`          | **New**.Use this binding to access the `openidm` [scripting functions](https://docs.pingidentity.com/pingidm/7.4/scripting-guide/scripting-func-ref.html) supported in IDM.                                                                                             | [`openidm`](#v2-openidm)                                              |

### `action`

| Legacy                                                                                                                                                                                 | Next-generation                                                                                              |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| ```javascript
var fr = JavaImporter(
    org.forgerock.openam.auth.node.api.Action;

 // Journey continues along the "false" path
action = fr.Action.goTo("false").build();      1
``` | ```javascript
 // Journey continues along the "false" path
action.goTo("false");                       1
``` |

1 No need to import the `Action` class to access the `goTo` method. Instead, call the `goTo` method directly on the `action` binding.

### `callbacksBuilder`

Use the `callbacksBuilder` object instead of importing `Callback` classes.

Learn more about using callbacks in [Callbacks](scripting-api-node.html#scripting-api-node-callbacks).

| Legacy                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             | Next-generation                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ```javascript
var fr = JavaImporter(                       1
  org.forgerock.openam.auth.node.api.Action,
  javax.security.auth.callback.NameCallback,
  javax.security.auth.callback.PasswordCallback,
  java.lang.String
);

if (callbacks.isEmpty()) {
  // Request callbacks
  action = fr.Action.send(                   2
    new fr.NameCallback("User Name"),
    new fr.PasswordCallback("Password", false)).build();
} else {
  // Callbacks returned with credentials
  var username =
    fr.String(callbacks.get(0).getName());
  var password =
    fr.String(callbacks.get(1).getPassword());

  sharedState.put("username", username);
  if (password === null || !password) {
    action = fr.Action.goTo("false").build();
  } else {                                   3
    transientState.put("password", password);
    action = fr.Action.goTo("true").build(); 4
  }
}
``` | ```javascript
if (callbacks.isEmpty()) {                   1
  // Request callbacks
  callbacksBuilder.nameCallback(
    "User Name", "User Name");
  callbacksBuilder.passwordCallback(
    "Password", false);
} else {
  // Callbacks returned with credentials
  var username =
    callbacks.getNameCallbacks().get(0);
  var password =
    callbacks.getPasswordCallbacks().get(0);

  nodeState.putShared("username", username);

  if (password === null || !password) {
    action.goTo("false");                    2
  } else {
    nodeState.putTransient("password",       3
        password);
    action.goTo("true");                     4
  }
}
``` |

1 Use `callbacksBuilder` to *request* callbacks, and the `callbacks` object to retrieve returned values.\
2 No need to explicitly call `send()`. The script sends every callback added to the `callbacksBuilder` when it completes.\
3 Use `nodeState.putShared()` instead of `sharedState.put()` and `nodeState.putTransient()` instead of `transientState.put()`.\
4 No need to set the outcome, because `action.goTo()` was invoked.

### `httpClient`

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

For more information, refer to [Access HTTP services](script-bindings.html#httpclient).

| Legacy                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                | Next-generation                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ```javascript
var fr = JavaImporter(
    org.forgerock.openam.auth.node.api.Action);

var requestURL =
    "https://example.com/authenticate";
var request = new
    org.forgerock.http.protocol.Request();

request.setUri(requestURL);                 1
request.setMethod("POST");
request.getHeaders().add("Content-Type",
    "application/json;");
request.getHeaders().add("Authorization",
    "Bearer abcd-1234");                    2
request.setEntity(JSON.stringify(
    {"username": "demo"}));

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

var responseCode =
    response.getStatus().getCode();         4

if (responseCode === 200) {
    action = fr.Action.goTo("true").build();
} else {
    action = fr.Action.goTo("false").build();
}
``` | ```javascript
 // import an external library to get token
var authLib = require('authLib');
var bearerToken =
    authLib.generateBearer(nodeState);

var options = {                             1
  method: "POST",
  headers: {
    "Content-Type": "application/json"
  },
  token: bearerToken,                       2
  body: {
    username: "demo"
  }
}

var requestURL =
    "https://example.com/authenticate";
var response = httpClient.send(
    requestURL, options).get();             3

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

1 Set the request options as a native JavaScript object, instead of setting parameters on a Request object.\
2 Use Library scripts to reuse common pieces of code; for example, to get an authentication token.\
3 Call `httpClient.send` with the request URL and options as separate arguments, instead of a Request object.\
4 Access response data directly using the methods and properties of the returned `response` object.

### `idRepository`

| Legacy                                                                                                                                                                                                                       | Next-generation                                                                                                                                                                                                                                                                                                                                                                                                           |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ```javascript
var username = "bjensen";

var mail = idRepository.getAttribute(
    username, "mail");                    1 2

idRepository.setAttribute(username, "mail",
    ["new@example.com"]);                    3
``` | ```javascript
var username = "bjensen";

var identity =
    idRepository.getIdentity(username);      1

var mail =
    identity.getAttributeValues("mail");     2

 // Does NOT automatically persist data
identity.setAttribute("mail",
    ["new@example.com"]);                    3

try {
  identity.store();                            4
} catch(e) {
    logger.error("Unable to persist attribute. " + e);
}
``` |

1 The `idRepository` object is no longer used to get attribute values. Instead, use the `getIdentity()` method of the new `org.forgerock.openam.scripting.api.identity.ScriptIdentityRepository` interface to get the identity object.\
2 Use the `identity` object, instead of `idRepository`, to get or set attribute values.\
3 Setting or adding attributes on the `identity` object does *not* persist data.\
4 You *must* explicitly persist changes by calling the `store` method.

### `logger`

The `com.sun.identity.shared.debug.Debug` logger class is deprecated and replaced by `org.forgerock.openam.scripting.logging.ScriptedLoggerWrapper`.

`ScriptedLoggerWrapper` provides a subset of the methods offered by [SLF4J](https://www.slf4j.org).

For more information, refer to [Log script messages](script-bindings.html#logger).

| Legacy                                                                                                                                                                                                                                                                              | Next-generation                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ```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);
``` | ```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);
``` |

### `nodeState`

| Legacy                                                                                                                                                                                                                                                                       | Next-generation                                                                                                                  |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| ```javascript
 // var username = sharedState.get("username");
                                             1
var username =
    nodeState.get("username").asString();    2
var attributes =                             3
    nodeState.get('objectAttributes').asMap();
``` | ```javascript
var username = nodeState.get("username");    2
var attributes =
    nodeState.getObject("objectAttributes"); 3
``` |

1 Deprecated `sharedState` and `transientState` bindings are no longer available. Use `nodeState.get()` instead. To store state values, use `nodeState.putShared()` or `nodeState.putTransient()` instead of `sharedState.put()` and `transientState.put()`.\
2 No need to call methods such as `asString()` or `asMap()`.\
3 New `getObject()` method to retrieve a map with values stored across different states. The map is immutable.

For more information about the `nodeState` binding, refer to [Access shared state data](scripting-api-node.html#scripting-api-node-nodeState).

### `openidm`

The new `openidm` binding lets you manage an IDM resource by calling scripting functions directly from a decision node script.

The following CRUDPAQ functions are supported:

* create

* read

* update

* delete

* patch

* action

* query

The following example shows the extensive code required in a legacy script to query the existence of a user by their email address in IDM, compared to the ease of using the `openidm` binding.

For further examples of how to use the `openidm` binding in your next-generation scripts, refer to [Access IDM scripting functions](scripting-api-node.html#scripting-api-node-openidm).

For details of other supported functions, refer to [Scripting functions](https://docs.pingidentity.com/pingidm/7.4/scripting-guide/scripting-func-ref.html).

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

| Legacy                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             | Next-generation                                                                                                                       |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------- |
| ```javascript
function lookupUser (email) {
  try {
    var idmUserEndpoint =
         + '/openidm/managed/user?
        _queryFilter=userName+eq+%22'
        + email + '%22';
    var request = new
        org.forgerock.http.protocol.Request();
    var accessToken =
        transientState.get("idmAccessToken");     1

    request.setMethod('GET');
    request.setUri(idmUserEndpoint);              1
    request.getHeaders().add('Authorization',
        'Bearer ' + accessToken);
    request.getHeaders().add('Content-Type',
        'application/json');
    request.getHeaders().add('Accept-API-Version',
        'resource=1.0');

    var httpResponse =
        httpClient.send(request).get();           1
    var responseCode =
        httpResponse.getStatus().getCode();
    if (responseCode === 200) {
      var response = JSON.parse(
          httpResponse.getEntity().getString());
      if (response && response.result &&
            response.result.length > 0) {
        // User found
        return {
          success: true,
          user: response.result[0]};
      } else {
        // User NOT found
        return { success: true, user: null };
      }
    } else {
      return {
        success: false,
        error: 'Error looking up user: ' + responseCode
      };
    }
  } catch (e) {
    return {
      success: false,
      error: 'Error querying user: ' + e.toString()
    };
  }
}
``` | ```javascript
openidm.query("managed/user", {        1
    "_queryFilter":`/userName eq '${email}'`
  },
  ["userName", "_id"]
);
``` |

1 Replace code that gets an `idmAccessToken` and uses the HTTP client object to invoke a request on an `/openidm/*` endpoint, with the direct use of the `openidm` binding.

## Exception handling when using next-generation script bindings

You must handle exceptions differently depending on whether the exception occurs within a JavaScript `Promise` or not.

Both types of exception handling can require that the Java exception class is allowlisted or marked as supported for you to access particular details about the exception, or another exception can be thrown.

|   |                                                                                                                                               |
| - | --------------------------------------------------------------------------------------------------------------------------------------------- |
|   | Next-generation doesn't support a configurable allowlist. Learn more in [Access Java classes](scripting-env.html#scripting-env-java-classes). |

### General exception handling

When you call a method on a script binding that throws an exception, the scripting engine wraps the exception object in a JavaScript error. You can use this to access the error message in the following way:

```javascript
try {
  myBinding.myMethod();
} catch (e) {
    // works without requiring support or allowlisting of the exception class
    logger.error(e.message);
}
```

You can access the underlying Java exception providing the exception class is allowlisted or the class and method are annotated as `@Supported`. For example:

```javascript
try {
  myBinding.myMethod();
} catch (e) {
    // throws an exception if getMyObject() isn't supported or the exception class isn't allowlisted
    myObject = e.javaException.getMyObject();
}
```

### Exception handling within a `Promise`

When you handle an exception in a `thenCatch` block of a `Promise`, the exception object isn't wrapped, so it still references the Java exception instead of a JavaScript error.

You can only access the exception object if the exception class is allowlisted or if the fields and methods you want to use are annotated with the `@Supported` annotation.

For example:

```javascript
var val = myBinding.methodReturningPromise()
  .then(() => {
    // function to handle the result of the promise
  })
  .thenCatch((e) => {
    // throws a new exception unless the "message" field is supported
    message = e.message;
    // throws an exception unless "getMyObject()" is supported or the exception class is allowlisted
    myObject = e.getMyObject();
    return false;
  }).get();
```
