Backchannel Notification node
RAPID only
The Backchannel Notification node adds data to the backchannel transaction from the backchannel journey, which the Backchannel Status node can read. This lets you send real-time status updates to the main journey from the backchannel journey.
Example
The following example shows how the Backchannel Notification node can be used in an out-of-band authentication journey to keep a help desk agent informed of progress while they’re verifying a user’s identity. The help desk agent can see real-time status updates when the user enters their password and when their credentials have been confirmed.
The example shows two journeys:
-
The main journey initializes a backchannel authentication journey and displays status updates to the help desk agent.
-
The backchannel journey is a simple authentication journey that adds status updates to the shared state and uses the Backchannel Notification node to add this data to the backchannel transaction.
Main journey
a The Page node with an Attribute Collector node prompts the help desk agent for the end user’s email address.
b The Identify Existing User node attempts to look up the username by matching the email address to the email address in an identity profile.
The lookup fails if no matching email address is found, or if more than one user profile uses the same email address.
c The Set Backchannel State Properties custom node writes the _id, objectAttributes, and username to the shared state.
This example uses the following configuration:
- Attribute list to set
-
_id
objectAttributes
username - Backchannel nodeState property
-
backchannel:data
How do I create this custom node?
The following steps provide the minimum configuration required to create this custom node. Learn more in custom nodes.
-
In the Advanced Identity Cloud admin UI, go to Journeys > Custom Nodes and click New Custom Node.
-
On the
New Custom Nodepage, enterSet Backchannel State Propertiesas the name and click Next. -
Add the following properties to the node and click Next:
- Attribute list to set
-
-
Name:
attributeListProperty -
Label:
Attribute list to set -
Type:
String -
Multi-Valued: Select this option.
-
Required: Select this option.
-
- Backchannel nodeState property
-
-
Name:
backchannelStateProperty -
Label:
Backchannel nodeState property -
Type:
String -
Required: Select this option.
-
Provide Default Value: Select this option.
-
Default Value:
backchannel:data
-
-
Set the following settings and click Next:
- Outcomes
-
Next - Error Outcome
-
Enabled
-
In the script editor, add the following script to define the behavior of the node:
(function () { logger.error(scriptName + "Node execution started"); //Get node properties var nodeStateProperty = properties.backchannelStateProperty; var attributeList = properties.attributeListProperty; //Loop to get and set attributes into the nodeStateProperty nodeState variable var out = {}; for (var i = 0; i < attributeList.length; i++) { var k = attributeList[i]; var v = nodeState.get(k); if (v !== null && v !== undefined) out[k] = v; } nodeState.putShared(nodeStateProperty, out); logger.error(scriptName + "Node execution completed"); action.goTo("Next"); })(); -
Click Save to create the custom node.
d The Backchannel Initialize node reads the username from the shared state.
-
If the
usernameis valid, the node generates a redirect URI to start the backchannel authentication journey. The node writes the redirect URI and the transaction ID of the backchannel transaction to the shared state, and the journey proceeds to the Backchannel Status node. -
If the
usernamecan’t be read, the journey follows the Error outcome and fails.
e The Backchannel Status node reads the transaction ID and provides status on the authentication request.
This example requires the following configuration:
- Record Transaction Data
-
Enabled - Transaction Data Key
-
transaction:data
f The Pending Wait node is a Polling Wait node that pauses this journey when the backchannel authentication request has a status of Pending. After 3 seconds, the journey returns to the Backchannel Status node.
g The In Progress Wait node is a Configuration Provider node. It imitates a Polling Wait node and uses a script to display messages from the backchannel journey to the help desk agent when the backchannel authentication has a status of In progress.
Sample Config Provider node script
var message;
var data = nodeState.get("transaction:data");
//Make sure this property name matches the Transaction Data Key configured in the Backchannel Status node
if (data) {
message = data["description"];
} else {
message = "Authentication in progress...";
}
config = {
"secondsToWait": 3,
"spamDetectionEnabled": false,
"spamDetectionTolerance": 3,
"waitingMessage": { "en": message },
"exitable": false,
"exitMessage": {}
};
h The User Message To Display custom node displays a message to the help desk agent when the backchannel authentication completes successfully.
This example uses the following configuration:
- Message to display
-
User successfully authenticated
How do I create this custom node?
The following steps provide the minimum configuration required to create this custom node. Learn more in custom nodes.
-
In the Advanced Identity Cloud admin UI, go to Journeys > Custom Nodes and click New Custom Node.
-
On the
New Custom Nodepage, enterUser Message to Displayas the name and click Next. -
Add the following property to the node and click Next:
- Message to display
-
-
Name:
message -
Label:
Message to display -
Type:
String -
Required: Select this option.
-
-
Set the following settings and click Next:
- Outcomes
-
Success
-
In the script editor, add the following script to define the behavior of the node:
(function () { logger.error(scriptName + "Node execution started"); if (callbacks.isEmpty()) { var userMessage = properties.message; callbacksBuilder.textOutputCallback(0, userMessage); } else { logger.error(scriptName + "Node execution completed"); action.goTo("Success"); } })(); -
Click Save to create the custom node.
Backchannel journey
This is a basic authentication journey that takes credentials and authenticates the user based on their existence in the backend identity store.
a The Page node includes a Display Username node and a Platform Password node. The username has been supplied in the shared state from the main journey. The user needs to enter their password.
b The Set Shared Or Transient State custom node adds data to the shared state that the Backchannel Notification node can send to the main journey.
This example uses the following configuration:
- State to update
-
SHARED - List of values to add to state
-
transaction:notify.description=User has entered their credentials
How do I create this custom node?
The following steps provide the minimum configuration required to create this custom node. Learn more in custom nodes.
-
In the Advanced Identity Cloud admin UI, go to Journeys > Custom Nodes and click New Custom Node.
-
On the
New Custom Nodepage, enterSet Shared Or Transient Stateas the name and click Next. -
Add the following properties to the node and click Next:
- State to update
-
-
Name:
state -
Label:
State to update -
Description:
nodeState.putShared or nodeState.putTransient -
Type:
String -
Required: Select this option.
-
Enumerated Values: Select this option and add the following
key:valuepairs:-
SHARED:SHARED -
TRANSIENT:TRANSIENT
-
-
Provide Default Value: Select this option.
-
Default Value:
SHARED
-
- List of values to add to state
-
-
Name:
values -
Label:
List of values to add to state -
Description:
In the form \"key=value\", \"key.subkey=value\", \"key=$key.subkey.subsubkey\", etc -
Type:
String -
Multi-Valued: Select this option.
-
Required: Select this option.
-
-
Set the following settings and click Next:
- Outcomes
-
Success
Error
-
In the script editor, add the following script to define the behavior of the node:
var outcome = "Success"; // ---------- helpers ---------- function isObject(x){ return x !== null && typeof x === "object"; } function toStr(x){ return (x === null || x === undefined) ? "" : String(x); } function resolveFromNodeState(path) { var parts = String(path).trim().split("."); if (parts.length === 0) return undefined; var base = nodeState.get(parts[0]); if (parts.length === 1) return base; var cur = base; for (var i = 1; i < parts.length; i++) { if (!isObject(cur)) return undefined; cur = cur[parts[i]]; if (cur === undefined || cur === null) return cur; } return cur; } function substitute(template) { try { return String(template).replace(/\$\{([^}]+)}/g, function(match, key){ var val = resolveFromNodeState(key); return (val !== undefined && val !== null) ? String(val) : match; }); } catch (e) { logger.error("Substitution error: " + e); outcome = "Error"; return template; } } function putState(stateName, key, value) { if (stateName === "SHARED") { nodeState.putShared(key, value); } else if (stateName === "TRANSIENT") { nodeState.putTransient(key, value); } else { logger.error("Invalid properties.state: " + stateName); outcome = "Error"; } } function maybeJson(value) { var s = String(value).trim(); if ((s.charAt(0) === "{" && s.charAt(s.length - 1) === "}") || (s.charAt(0) === "[" && s.charAt(s.length - 1) === "]")) { try { return JSON.parse(s); } catch (e) {} } return value; } // Define BEFORE use to avoid issues var processPair = function(stateName, pair) { try { var str = String(pair); var eqIdx = str.indexOf("="); if (eqIdx < 0) { logger.error("Invalid key=value pair (no '='): " + str); outcome = "Error"; return; } var lh = str.substring(0, eqIdx).trim(); var rh = str.substring(eqIdx + 1).trim(); var result = maybeJson(substitute(rh)); var dotIdx = lh.indexOf("."); if (dotIdx >= 0) { var baseKey = lh.substring(0, dotIdx); var subKey = lh.substring(dotIdx + 1); var current = nodeState.get(baseKey); if (!isObject(current)) current = {}; current[subKey] = result; putState(stateName, baseKey, current); } else { putState(stateName, lh, result); } } catch (e) { logger.error("Error processing pair '" + pair + "': " + e); outcome = "Error"; } }; // ---------- main ---------- try { var stateName = properties.state; var values = properties.values; if (!values) { logger.error("properties.values is empty"); outcome = "Error"; } else if (values.iterator && typeof values.length !== "number") { var it = values.iterator(); while (it.hasNext()) { processPair(stateName, String(it.next())); } } else { for (var i = 0; i < values.length; i++) { processPair(stateName, String(values[i])); } } } catch (outerError) { logger.error("Unexpected error: " + outerError); outcome = "Error"; } -
Click Save to create the custom node.
c The Backchannel Notification node reads the shared state and sends a status update to the main journey to inform the help desk agent that the user has entered their credentials.
d The Data Store Decision node validates the username-password credentials.
e The Set Shared Or Transient State custom node adds data to the shared state that the Backchannel Notification node can send to the main journey. This is the custom node you created earlier in this example.
This instance of the node uses the following configuration:
- State to update
-
SHARED - List of values to add to state
-
transaction:notify.description=user’s credentials are valid
f The Backchannel Notification node reads the shared state and sends a status update to the main journey to inform the help desk agent that the user’s credentials match those stored in the data store.
Availability
| Product | Available? |
|---|---|
PingOne Advanced Identity Cloud |
Yes |
PingAM (self-managed) |
Yes |
Ping Identity Platform (self-managed) |
Yes |
Inputs
This node reads data from the incoming node state using the key specified in the Data Key. The key value must be a JSON object.
Implement a node earlier in the journey to add data to the incoming node state using this key. For example, you could use custom nodes or a Scripted Decision node.
Configuration
| Property | Usage |
|---|---|
Data Key |
The shared state key that contains the data you want to add to the backchannel transaction. For example This key is used to read data from the incoming node state. |
Outcomes
- Success
-
The backchannel notification was successfully sent.
- Error
-
An error occurred when sending the backchannel notification.
Errors
The node can log the following errors:
-
Failed to update backchannel transactionAn error occurred when the node attempted to update the backchannel transaction with the data from the incoming node state.
The node can log the following warnings:
-
Transaction ID not found in contextThe transaction ID is missing from the incoming request context.
-
Data in state at dataKey data key was not found or incorrect type, not updating transaction.The Data Key configured for the node doesn’t exist in the incoming node state, or it exists but contains invalid data.