---
title: Scripted decision node API
description: A Scripted Decision node calls server-side Groovy or JavaScript to set the outcome for the node programmatically and determine the path the authentication journey takes. The script can perform actions before setting the outcome.
component: pingam
version: 7.3
page_id: pingam:authentication-guide:scripting-api-node
canonical_url: https://docs.pingidentity.com/pingam/8.1/am-scripting/scripting-api-node.html
llms_txt: https://docs.pingidentity.com/pingam/llms.txt
docs_for_agents: https://developer.pingidentity.com/build-with-ai/docs-for-agents.md
keywords: ["Authentication", "Sessions", "Nodes &amp; Trees", "Scripting"]
section_ids:
  scripted-decision-node-bindings: Scripted decision node bindings
  scripting-api-node-requestHeaders: Access request header data
  methods: Methods
  scripting-api-node-requestParameters: Access request parameter data
  methods_2: Methods
  scripting-api-node-nodeState: Access shared state data
  methods_3: Methods
  scripting-api-node-id-repo: Access profile data
  methods_4: Methods
  scripting-api-node-sessionProperties: Set session properties
  scripting-api-node-existingSession: Access existing session properties
  methods_5: Methods
  scripting-api-node-callbacks: Callbacks
  scripting-api-authn-secrets: Accessing credentials and secrets
  methods_6: Methods
  scripting-api-node-audit-logging: Audit information
---

# Scripted decision node API

A [Scripted Decision node](https://docs.pingidentity.com/auth-node-ref/7.3/auth-node-scripted-decision.html) calls server-side Groovy or JavaScript to set the outcome for the node programmatically and determine the path the authentication journey takes. The script can perform actions before setting the outcome.

To create and manage decision scripts, refer to [Manage scripts (UI)](../scripting-guide/manage-scripts-console.html). Use the script type Decision node script for authentication trees.

A script can set the outcome directly, or use the `Action` interface:

* `outcome`

  Assign string values to the `outcome` variable.

  * JavaScript

  ```javascript
  if (expectedCondition) {
    outcome = "true"
  } else {
    outcome = "false"
  }
  ```

  When configuring the [Scripted Decision node](https://docs.pingidentity.com/auth-node-ref/7.3/auth-node-scripted-decision.html), add the two outcomes `true` and `false` in Outcomes. Each outcome appears as a node endpoint that you connect to other nodes in the tree.

  The outcome strings are not limited to `true` and `false`. Specify a value for each possible outcome and as many outcomes as required by the tree.

* `Action`

  Use the `Action` interface to define the `outcome` and/or to perform an operation, for example, by chaining with `ActionBuilder` functions.

  > **Collapse: Example  functions:**
  >
  > | Method                                                                                                                                | Information                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
  > | ------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  > | `public ActionBuilder putSessionProperty(String key, String value)`                                                                   | Add a session property.Refer to [Set session properties](#scripting-api-node-sessionProperties).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
  > | `public ActionBuilder removeSessionProperty(String key)`                                                                              | Remove an existing session property.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
  > | `public ActionBuilder withDescription(String description)`                                                                            | Set a description for the action.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
  > | `public ActionBuilder withErrorMessage(String message)`                                                                               | Set an error message to display to the end user when the journey reaches the Failure node.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
  > | `public ActionBuilder withIdentifiedIdentity(AMIdentity id)``public ActionBuilder withIdentifiedIdentity(String username, IdType id)` | Set the identity, authenticated or not, of the user or agent verified to exist in an identity store.Use these methods to record the type of identified user. If the advanced server property, `org.forgerock.am.auth.trees.authenticate.identified.identity` is set to true, AM uses the stored identified identities to decide who to log in.This lets the authentication tree engine correctly resolve identities that have the same username.For more information, refer to [advanced server properties](../reference/deployment-configuration-reference.html#org.forgerock.am.auth.trees.authenticate.identified.identity). |
  > | `public ActionBuilder withLockoutMessage(String message)`                                                                             | Set an error message to display to the end user when the account is locked or inactive.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
  > | `public ActionBuilder withStage(String stage)`                                                                                        | Set a stage name to return to the client to aid the rendering of the UI. The property is only sent if the script also sends callbacks.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
  >
  > For more information, refer to [ActionBuilder](../_attachments/apidocs/org/forgerock/openam/auth/node/api/Action.ActionBuilder.html).

  * JavaScript

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

  if (expectedCondition) {
    // Set outcome to "true", and set a custom session property:
    action = fr.Action.goTo("true").putSessionProperty("customKey", "customValue").build()
  } else {
    // Set outcome to "false", and add an "errorMessage" in the shared node state:
    action = fr.Action.goTo("false").withErrorMessage("Friendly error description.").build()
  }
  ```

  An outcome specified with the `Action.goTo` method overrides the value set for the `outcome` variable:

  * JavaScript

  ```javascript
  action = Action.goTo("false").build() // Evaluation continues along the "false" outcome.
  outcome = "true"                      // No effect.
  ```

  A script can also use the `Action` interface to set [session properties](#scripting-api-node-sessionProperties) and [callbacks](#scripting-api-node-callbacks). For details about the `Action` interface, refer to the Javadoc for [Action](../_attachments/apidocs/org/forgerock/openam/auth/node/api/Action.html).

## Scripted decision node bindings

A script has access to AM *bindings*, objects that AM injects into the script execution context:

| Binding              | Information                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `auditEntryDetail`   | Add information to the AM audit logs.Refer to [Audit information](#scripting-api-node-audit-logging).                                                                                                                                                                                                                                                                                                                                                             |
| `callbacks`          | Request additional data from the user using a callback.Refer to [Callbacks](#scripting-api-node-callbacks).                                                                                                                                                                                                                                                                                                                                                       |
| `existingSession`    | If the user has previously authenticated and has a session, use this variable to access the properties of that session.This binding is only present when performing a session upgrade. Any properties added by nodes earlier in the tree only appear on the user's new session when the journey completes; such properties are not available in the `existingSession` binding.Refer to [Access existing session properties](#scripting-api-node-existingSession). |
| `httpClient`         | Make outbound HTTP calls.For details, refer to the Javadoc for [ChfHttpClient](../_attachments/apidocs/org/forgerock/http/client/ChfHttpClient.html).                                                                                                                                                                                                                                                                                                             |
| `idRepository`       | Access the data stored in the user's profile.Refer to [Access profile data](#scripting-api-node-id-repo).                                                                                                                                                                                                                                                                                                                                                         |
| `logger`             | The logger instance for the script.Logger names use the format `scripts.AUTHENTICATION_TREE_DECISION_NODE.<script UUID>.(<script name>)`.Refer to [Debug logging](../maintenance-guide/debug-logging.html).                                                                                                                                                                                                                                                       |
| `realm`              | Return 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`.                                                                                                                                                                                                                                                                                                 |
| `requestHeaders`     | Access the HTTP headers provided in the login request.Refer to [Access request header data](#scripting-api-node-requestHeaders).                                                                                                                                                                                                                                                                                                                                  |
| `requestParameters`  | Access the HTTP request parameters provided in the login request.Refer to [Access request parameter data](#scripting-api-node-requestParameters).                                                                                                                                                                                                                                                                                                                 |
| `resumedFromSuspend` | Boolean—​True if evaluation has resumed after suspension; for example, after sending an email and receiving the response.                                                                                                                                                                                                                                                                                                                                         |
| `secrets`            | Access the secrets configured for AM in the environment.For details, refer to the Javadoc for [ScriptedSecrets](../_attachments/apidocs/org/forgerock/openam/scripting/api/secrets/ScriptedSecrets.html).                                                                                                                                                                                                                                                         |
| `nodeState`          | Access data set by previous nodes in the tree, or store data to be used by subsequent nodes.Refer to [Access shared state data](#scripting-api-node-nodeState).                                                                                                                                                                                                                                                                                                   |

## Access request header data

A script can access the headers in the login request with the methods of the `requestHeaders` object.

The script has access to a copy of the headers. Changing their values does not affect the request.

### Methods

* `String[] requestHeaders.get(String headerName)`

  Returns an array of the values in the named request header, or `null`, if the property is not set.

  Header names are case-sensitive.

  * JavaScript

  ```javascript
  if (requestHeaders.get("user-agent").get(0).indexOf("Chrome") !== -1) {
      outcome = "true"
  } else {
      outcome = "false"
  }
  ```

## Access request parameter data

A script can access the query parameters in the login request with the methods of the `requestParameters` object.

The script has access to a copy of the parameters. Changing their values does not affect the request.

### Methods

* `String[] requestParameters.get(String parameterName)`

  Return an array of the values in the named request parameter, or `null`, if the parameter is not available.

  * JavaScript

  ```javascript
  var service
  var authIndexType = requestParameters.get("authIndexType")
  if (authIndexType && String(authIndexType.get(0)) === "service") {
      service = requestParameters.get("authIndexValue").get(0)
  }

  if (service) {
      nodeState.putShared("service", service)
  }

  outcome = "true"
  ```

  |   |                                                                                                                                                   |
  | - | ------------------------------------------------------------------------------------------------------------------------------------------------- |
  |   | In JavaScript, the `requestParameters` values have a `typeof` of *object*.Convert the values to strings before using strict equality comparisons. |

## Access shared state data

A script can access the shared state of the tree with the methods of the `nodeState` object. There are three types of state:

* Shared

  Non-sensitive state.

* Transient

  Sensitive state.

  Transient state data is never sent back to the user's browser in a callback so does not need to be encrypted.

* Secure

  Encrypted sensitive state.

  Secure state data is sent back to the user's browser encrypted as part of the shared state object.

Transient state data is *promoted* to secure state data when:

* A callback to the user is about to occur.

* A downstream node is detected in the journey, requesting data in the transient state as script input.

|   |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | Unless the downstream node explicitly requests the secure state data by name, the authentication journey removes it from the node state after processing the next callback.For example, a node in a registration journey stores a user's password in transient state. The node sends a callback to the user before an inner tree node, downstream in the journey, consumes that password. As part of the callback, the journey assesses what to add to the secure state. It does this by checking the state inputs that downstream nodes in the journey require. Nodes that *only* request `*` are ignored, as this would result in putting everything that's in transient state into secure state, and retaining sensitive information longer than necessary.If a downstream node requires the password, it must therefore explicitly request it as state input, even if it lists the `*` wildcard as input. |

AM stores shared state properties as name-value pairs. Property names are case-sensitive.

### Methods

For additional methods and details, refer to the Javadoc for [NodeState](../_attachments/apidocs/org/forgerock/openam/auth/node/api/NodeState.html).

* `JsonValue nodeState.get(String propertyName)`

  Returns the value of the named property.

  The value may come from the transient, secure, or shared states, in that order. If the same property is available in several states, the method returns the value of the property in the transient state first.

  If the property is not set, the method returns `null`.

  * JavaScript

  ```javascript
  var currentAuthLevel = nodeState.get("authLevel")
  var thePassword = nodeState.get("password")

  outcome = "true"
  ```

* `NodeState nodeState.putShared(String propertyName, String propertyValue)`

  Sets the value of the named shared state property.

  * JavaScript

  ```javascript
  try {
    var thePassword = nodeState.get("password").asString()
  } catch (e) {
    nodeState.putShared("errorMessage", e.toString())
  }

  outcome = "true"
  ```

* `NodeState nodeState.putTransient(String propertyName, String propertyValue)`

  Sets the value of the named transient state property.

  * JavaScript

  ```javascript
  nodeState.putTransient("sensitiveKey", "sensitiveValue")

  outcome = "true"
  ```

## Access profile data

A script can access profile data through the methods of the `idRepository` object.

### Methods

* `Set idRepository.getAttribute(String userName, String attributeName)`

  Returns the values of the named attribute for the named user.

- JavaScript

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

var username = nodeState.get("username").asString();
var attribute = "mail";

// Returns all values, for example: [test@example.com, user@example.com]
idRepository.getAttribute(username, attribute).toString();

// Returns the first value, for example:  test@example.com
idRepository.getAttribute(username, attribute).iterator().next();

// Returns a value at the specified index, for example: user@example.com
idRepository.getAttribute(username, attribute).toArray()[1];

// If no attribute by this name is found, the result is an empty array: []
idRepository.getAttribute(username, "non-existent-attribute").toString();

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

* `void idRepository.setAttribute(String userName, String attributeName, Array attributeValues)`

  Sets the named attribute as specified by the attribute value for the named user, and persists the result in the user's profile.

  * JavaScript

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

  var username = nodeState.get("username").asString();

  // Set attribute using the idRepository object
  idRepository.setAttribute(username, "mail", ["test@example.com"]);

  try {
    // check setAttribute was successful
    var mail = idRepository.getAttribute(username, "mail").iterator().next();
    action = fr.Action.goTo("true").build();
  } catch(e) {
    logger.error("Unable to persist attribute. " + e);
    action = fr.Action.goTo("false").build();
  }
  ```

* `void idRepository.addAttribute(String userName, String attributeName, String attributeValue)`

  Add an attribute value to the list of attribute values associated with the attribute name for a particular user.

  * JavaScript

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

  var username = nodeState.get("username").asString();
  var attr = "mail";

  // get number of existing attribute values
  var mail = idRepository.getAttribute(username, attr).toArray();

  // Add attribute using the idRepository object
  idRepository.addAttribute(username, attr, ["test@example.com"]);

  // check addAttribute was successful
  var updatedmail = idRepository.getAttribute(username, attr).toArray();
  if (updatedmail.length > mail.length) {
  action = fr.Action.goTo("true").build();
  } else {
  logger.error("Unable to add attribute.");
  action = fr.Action.goTo("false").build();
  }
  ```

## Set session properties

A script can create session properties with the fields and methods of the [Action](../_attachments/apidocs/org/forgerock/openam/auth/node/api/Action.html) interface.

The following example sets the outcome to `true`, and adds a custom session property:

* JavaScript

```javascript
var goTo = org.forgerock.openam.auth.node.api.Action.goTo
action = goTo("true").putSessionProperty("mySessionProperty", "myPropertyValue").build()
```

Add the script to a [Scripted Decision node](https://docs.pingidentity.com/auth-node-ref/7.3/auth-node-scripted-decision.html) in your authentication tree.

To verify that the property was set, call the [sessions REST endpoint](../sessions-guide/managing-sessions-REST.html#rest-api-session-information) after a user authenticates.

If you've added the property name to the [session property allowlist](../reference/global-services-configuration.html#global-amsessionpropertywhitelist), it appears in the `properties` object of the JSON response. For example:

```json
{
  "username": "014c54bd-6078-4639-8316-8ce0e7746fa4",
  "universalId": "id=014c54bd-6078-4639-8316-8ce0e7746fa4,ou=user,o=alpha,ou=services,ou=am-config",
  "realm": "/alpha",
  "latestAccessTime": "2022-10-31T11:03:25Z",
  "maxIdleExpirationTime": "2022-10-31T11:33:25Z",
  "maxSessionExpirationTime": "2022-10-31T13:03:24Z",
  "properties": {
    "AMCtxId": "de5abe95-db97-4354-9d32-aab660ea23a3-4252446",
    "mySessionProperty": "myPropertyValue"
  }
}
```

## Access existing session properties

A script can access existing session properties during a session upgrade request with the `existingSession.get` method.

### Methods

* `String existingSession.get(String propertyName)`

  Returns the string value of the named existing session property, or `null`, if the property is not set.

  If the current request is not a session upgrade and does not provide an existing session, the `existingSession` variable is not declared. Check for a declaration before attempting to access the variable.

  * JavaScript

  ```javascript
  if (typeof existingSession !== 'undefined') {
      var existingAuthLevel = existingSession.get("AuthLevel")
  } else {
      nodeState.putShared("errorMessage", "Variable existingSession not declared - not a session upgrade.")
  }

  outcome = "true"
  ```

## Callbacks

A script can use callbacks to provide or prompt for additional information during the authentication process.

The following script uses the `NameCallback` callback to request a "Nickname" value from the user. It adds the nickname to the `nodeState` object for use by subsequent nodes in the authentication tree:

* JavaScript

```javascript
var fr = JavaImporter(
  org.forgerock.openam.auth.node.api,
  javax.security.auth.callback.NameCallback
)

if (callbacks.isEmpty()) {
  action = fr.Action.send(new fr.NameCallback("Enter Your Nickname")).build()
} else {
  nodeState.putShared("Nickname", callbacks.get(0).getName())
  action = fr.Action.goTo("true").build()
}

outcome = "true";
```

For a list of supported callbacks, refer to [Supported callbacks](authn-supported-callbacks.html).

## Accessing credentials and secrets

Scripts used in a scripted decision node can access the secrets configured in [AM secret stores](../security-guide/secrets-certs-keys.html) *on the file system*.

For example, a script can access credentials or secrets defined in a file system secret volume in order to make outbound calls to a third-party REST service, without hard-coding those credentials in the script.

### Methods

* `String secrets.getGenericSecret(String secretId)`

  Returns the value of the specified secret ID.

  If the secret ID is defined at the realm level, its value is returned; otherwise, the script returns the value defined at the global level.

  Only secret IDs that begin with the string `scripted.node.` are accessible to scripts.

  For more information on creating secret IDs in a secret store, refer to [Secret stores](../security-guide/secret-stores.html).

  Use the following functions to format the returned secret value:

  * `getAsBytes()`

    Retrieve the secret value in `byte[]` format.

  * `getAsUtf8()`

    Retrieve the secret value in UTF-8 format.

  The following example scripts show how to get the value (`passwd`) from a secret ID named `scripted.node.secret.id`. They use the value 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:

  * JavaScript

  * Groovy

  ```javascript
  var username = "demoUser"
  var password = secrets.getGenericSecret("scripted.node.secret.id").getAsUtf8()

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

  var request = new org.forgerock.http.protocol.Request()
  request.setMethod("GET")
  request.setUri("http://httpbin.org/basic-auth/demoUser/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.error("Script result: " + JSON.stringify(jsonResult))
  if (jsonResult.hasOwnProperty("authenticated")) {
      logger.error("outcome = success")
      outcome = "success"
  }  else {
      logger.error("outcome = failure")
      outcome = "failure"
  }
  ```

  ```groovy
  def username = "demoUser"
  def password = secrets.getGenericSecret("scripted.node.secret.id").getAsUtf8()

  def auth = java.util.Base64.getEncoder().encodeToString((username + ":" + password).getBytes())

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

  def response = httpClient.send(request).get()
  if (response.status.successful) {
      logger.error("outcome = success")
      outcome = "success"
  }  else {
      logger.error("outcome = failure")
      outcome = "failure"
  }
  ```

  |   |                                                                                                                                                                                                                                                                                                                                             |
  | - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  |   | To use these sample scripts, 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 [Security](../scripting-guide/script-engine-security.html). |

## Audit information

Use a script to add information to audit log entries with the `auditEntryDetail` variable.

AM appends the value of the variable to the [authentication audit logs](../security-guide/sec-maint-audit-ref.html#authentication-log-format).

For JavaScript, the variable must be a string. This example adds the username and email address to the log entry:

```javascript
var username = nodeState.get("username").asString();
var email = idRepository.getAttribute(username,"mail").iterator().next().toString();

var detailStr = ("Extra Audit: [" + username + "] Email address: " + email).toString();
auditEntryDetail= detailStr;

outcome = "true";
```

AM records the audit string in the `entries > info > nodeExtraLogging > auditInfo` field of the authentication log entry:

```json
{
    "_id": "31a9caa2-1439-4088-813f-a60c5f083a45-7725962",
    "timestamp": "2022-12-13T17:22:14.818Z",
    "eventName": "AM-NODE-LOGIN-COMPLETED",
    "transactionId": "31a9caa2-1439-4088-813f-a60c5f083a45-7725948",
    "trackingIds": [
        "31a9caa2-1439-4088-813f-a60c5f083a45-7725576"
    ],
    "principal": [
        "bjensen"
    ],
    "entries": [
        {
            "info": {
                "nodeOutcome": "true",
                "treeName": "Example",
                "displayName": "Audit Entry",
                "nodeType": "ScriptedDecisionNode",
                "nodeId": "275a8aeb-7a61-4c70-acc2-decb1e0bc139",
                "authLevel": "0",
                "nodeExtraLogging": {
                    "auditInfo": "Extra Audit: [bjensen] Email address: bjensen@example.com"
                }
            }
        }
    ],
    "realm": "/alpha",
    "component": "Authentication"
}
```

For more information about logging, refer to [Audit logging](../security-guide/audit-logging.html).
