Identity Cloud

Scripted Decision node

The Scripted Decision node lets you run a server-side script in an authentication journey. It exists to let you connect the script to other nodes with the journey editor.

The script makes a decision to set the outcome for the node.

Compatibility

Product Compatible?

ForgeRock Identity Cloud

Yes

ForgeRock Access Management (self-managed)

Yes

ForgeRock Identity Platform (self-managed)

Yes

Inputs

Scripted Decision node inputs depend entirely on the node’s server-side script.

The script has access to the authentication context including:

  • Headers from the request

  • Query string parameters from the request

  • Secrets configured for the realm

  • Shared state data

  • User profile data

The script can use callbacks to prompt the user for information.

For details about the inputs available to the script, refer to Scripted decision node API.

You can restrict available inputs using the Script Inputs field when configuring the node.

Dependencies

A Scripted Decision node depends on a Journey Decision Node script you create before you configure the node.

Configuration

Property Usage

Script

Select the script to run from the drop-down list.

Outcomes

Enter one string for each outcome the script can set.

The node shows only the outcomes you configure. If you omit an outcome string, you can’t connect it in the journey editor.

When the script sets an outcome you omitted in the configuration, it logs a warning. This can prevent the journey from completing successfully.

Script Inputs

Optionally, list the shared state data properties required by the script.

If you change the setting, you must declare each property or null for no properties.

Default: *. The script has access to all shared and transient state data.

Sensitive data in transient state upgrades to secure state if:

  • The node sends a callback to the user.

  • The node detects a downstream node requesting the transient state data as 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 in transient state into secure state, and retaining sensitive information longer than necessary.

If a downstream node requires the password, it must explicitly request it as state input, even if it lists the * wildcard as input.

Script Outputs

Optionally, list the shared state data properties the node expects the script to set.

If you change the setting, you must declare each property or null for no properties.

Default: *. The node doesn’t validate the script outputs at all.

Outputs

Scripted Decision node outputs, such as updates to shared state data, depend entirely on the node’s server-side script.

You can restrict available outputs using the Script Outputs field when configuring the node.

Outcomes

The script defines the outcomes by setting its outcome variable to an outcome string before returning.

You include all possible outcome strings from the script in the Outcome field when configuring the node.

The authentication journey continues along the outcome path from the script.

Errors

The server-side script can log messages.

The node logs the following warning messages:

Warnings:

  • Found an action result from scripted node, but it was not an Action object: An action in a legacy script didn’t return an object with type Action.

  • Found an action result from scripted node, but it was not an ActionWrapper object: An action in a next generation script didn’t return an object with type ActionWrapper.

  • invalid script outcome <outcome>: The <outcome> is missing in the Outcome field of the node configuration.

  • invalid script outcome <action-outcome> in action: The <action-outcome> is missing in the Outcome field of the node configuration.

  • script outcome error: The script set an outcome not found in the Outcome field of the node configuration.

Examples

You use a Scripted Decision node when no other available node does what you need.

In this example, the node depends on the following JavaScript Journey Decision Node script. The script gets the user’s names from their profile and stores a message in a shared state property:

  • Next-generation

  • Legacy

// Get the username from shared state data:
var username = nodeState.get('username')

// Get the given name(s) and surname(s) from the user profile:
var profile = idRepository.getIdentity(username)
var givenname = profile.getAttributeValues('givenName')
var surname = profile.getAttributeValues('sn')
if (!(givenname && surname)) {
  var error = `Failed to get names for ${username}: ${givenname} ${surname}`
  action.goTo('Failure').withErrorMessage(error);
} else {
  // Record who authenticated in the shared state data:
  var firstGivenName = givenname[0]
  var firstSurname = surname[0]
  var now = new Date().toLocaleString()
  var message = `${firstGivenName} ${firstSurname} logged in at ${now}.`
  nodeState.putShared('message', message)
  action.goTo('Success');
}
var goTo = org.forgerock.openam.auth.node.api.Action.goTo

// Get the username from shared state data:
var username = nodeState.get('username').asString()

// Get the given name(s) and surname(s) from the user profile:
var profile = idRepository.getIdentity(username)
var givenname = profile.getAttributeValues('givenName')
var surname = profile.getAttributeValues('sn')
if (!(givenname && surname)) {
  var error = `Failed to get names for ${username}: ${givenname} ${surname}`
  action = goTo('Failure').withErrorMessage(error).build()
} else {
  // Record who authenticated in the shared state data:
  var firstGivenName = givenname[0]
  var firstSurname = surname[0]
  var now = new Date().toLocaleString()
  var message = `${firstGivenName} ${firstSurname} logged in at ${now}.`
  nodeState.putShared('message', message)
  action = goTo('Success').build()
}

Notice the script sets the outcomes using the Action.goTo(outcome) function.

The journey is as follows:

Journey with a [.label]#Scripted Decision# node
  1. The Page node prompts the user for their username and password.

  2. The Identity Store Decision node checks the username and password with those in the identity store.

    The node configuration enables the optional Username as Universal Identifier setting. As a result, the nodeState.get('username').asString() function in the script returns the user’s _id. The username in idRepository.getIdentity(username) must be the _id, not the userName, to get the attribute from the user’s profile.

  3. The Scripted Decision node runs the script and has the following settings:

    Script

    The name of the script

    Outcomes

    Success, Failure

    Script Inputs

    username

    Script Outputs

    *

    Notice the Outcomes setting lists all outcome strings from the script.

  4. The Increment Login Count node updates the count on successful authentication.

  5. The Inner Tree Evaluator node refers to another journey to perform more steps.

    This node is optional.

If you activate debug mode for the journey and select Enable Debug Popup, you find the message in the debug popup window when authenticating:

{
  "universalId": "id=<_id>,ou=user,o=alpha,ou=services,ou=am-config",
  "transactionId": "<transaction-id>",
  "password": "<password>",
  "pageNodeCallbacks": {
    "0": 0,
    "1": 1
  },
  "realm": "/alpha",
  "message": "Babs Jensen logged in at August 16, 2023 9:55:33 AM UTC.",
  "authLevel": 0,
  "objectAttributes": {
    "password": "<password>"
  },
  "username": "id=<_id>"
}
Copyright © 2010-2024 ForgeRock, all rights reserved.