Use case overview
ForgeRock Identity Cloud is architected on top of REST services, which enables almost all policy configurations and identity operations to be managed through REST API calls. One of Identity Cloud’s most powerful features is the ability to create custom endpoints that can extend the default ForgeRock REST API with new endpoints to perform a wide range of tasks, including those with custom logic.
In this example use case, we’ll demonstrate a custom endpoint by configuring a REST endpoint that invokes a journey to generate a one-time passcode (OTP) on behalf of an end user. This example shows that journeys are, in themselves, REST endpoints.
Steps to achieve this use case
This example use case has two stages:
Create a journey that returns an OTP
First, we’ll create a journey that returns a generated OTP. The journey includes three scripted nodes, with the following scripts:
- Return OTP
- OTP valid
- OTP invalid
Return OTP
Create the following Return OTP
script. This script returns a generated OTP using a TextOutputCallback, which represents a callback used to display a message.
/* Return OTP
*
* Author: volker.scheuber@forgerock.com
*
* Return the generated OTP using a TextOutputCallback.
*
* This script does not need to be parameterized. It will work properly as is.
*
* The Scripted Decision Node needs the following outcomes defined:
* - true
*/
outcome = "true";
var fr = JavaImporter(
org.forgerock.openam.auth.node.api.Action,
javax.security.auth.callback.TextOutputCallback
)
if (callbacks.isEmpty()) {
action = fr.Action.send(
new fr.TextOutputCallback(
fr.TextOutputCallback.INFORMATION,
nodeState.get("oneTimePassword").asString()
)
).build()
}
else {
action = fr.Action.goTo(outcome).build();
}
OTP Valid
Create the following OTP Valid
script. This script returns the TextOutputCallback indicating the provided OTP was valid.
/* OTP Valid
*
* Author: volker.scheuber@forgerock.com
*
* Return TextOutputCallback indicating the provided OTP was valid.
*
* This script does not need to be parametrized. It will work properly as is.
*
* The Scripted Decision Node needs the following outcomes defined:
* - true
*/
outcome = "true";
var fr = JavaImporter(
org.forgerock.openam.auth.node.api.Action,
javax.security.auth.callback.TextOutputCallback
)
if (callbacks.isEmpty()) {
action = fr.Action.send(
new fr.TextOutputCallback(
fr.TextOutputCallback.INFORMATION,
"VALID"
)
).build()
}
else {
action = fr.Action.goTo(outcome).build();
}
OTP Invalid
Create the following OTP Invalid
script. This script returns the TextOutputCallback indicating the provided OTP was invalid.
/* OTP Invalid
*
* Author: volker.scheuber@forgerock.com
*
* Return TextOutputCallback indicating the provided OTP was invalid.
*
* This script does not need to be parametrized. It will work properly as is.
*
* The Scripted Decision Node needs the following outcomes defined:
* - true
*/
outcome = "true";
var fr = JavaImporter(
org.forgerock.openam.auth.node.api.Action,
javax.security.auth.callback.TextOutputCallback
)
if (callbacks.isEmpty()) {
action = fr.Action.send(
new fr.TextOutputCallback(
fr.TextOutputCallback.INFORMATION,
"INVALID"
)
).build()
}
else {
action = fr.Action.goTo(outcome).build();
}
Create the journey
-
Sign in to the Identity Cloud admin UI using your admin tenant URL, in the format
https://<tenant-name>/am/XUI/?realm=/#/
. -
Go to Journeys > New Journey.
-
Enter a unique name for the OTP endpoint journey (for example,
OTPEndpoint
), select which identities will authenticate using this journey, (optionally) enter a journey description, and click Save. -
Create a journey similar to this:
Node descriptions:
-
Anonymous - This Anonymous User Mapping node allows users to log in to an application or website without providing credentials.
-
HOTP Generator - Creates a string of random digits of the specified length for use as a one-time password. See HOTP Generator node for further information.
-
Return OTP - This Scripted Decision node returns the generated OTP. See Step 5 for further information on configuring this node.
-
Validate OTP - This OTP Collector Decision node requests and verifies the returned OTP.
-
OTP Valid - This Scripted Decision node returns a TextOutputCallback indicating the provided OTP was valid. See Step 6 for further information on configuring this node.
-
OTP Invalid - This Scripted Decision node returns a TextOutputCallback indicating the provided OTP was invalid. See Step 7 for further information on configuring this node.
-
-
Click on the Return OTP node (Scripted Decision node), select the
Return OTP
script you created previously, and entertrue
in the Outcomes. -
Click on the OTP Valid node (Scripted Decision node), select the
OTP Valid
script you created previously, and entertrue
in the Outcomes. -
Click on the OTP Invalid node (Scripted Decision node), select the
OTP Invalid
script you created previously, and entertrue
in the Outcomes. -
Click Save to save the journey.
Configure a custom endpoint that invokes the OTP journey
-
In the Identity Cloud admin UI, go to Scripts > Custom Endpoints.
-
Click New Endpoint.
-
Enter a name and optional description for the custom endpoint.
-
Replace the default script with a script similar to the following.
Replace
<journey-name>
with the name of your OTP journey, for example,"OTPEndpoint"
and<tenant name>
with your Identity Cloud tenant.//* OTP generation and validation *// (function () { var journey = "<journey-name>"; var txId = context.current.parent.parent.parent.headers["x-forgerock-transactionid"][0]; logger.info("otp: Method: {} txId: {}", request.method, txId); if (request.method === 'create') { // POST var postParams = { "url": "https://<tenant-name>/am/json/alpha/authenticate?authIndexType=service&authIndexValue="+journey, "method": "POST", "headers": { "Accept-API-Version": [ "resource=2.0, protocol=1.0" ], "Content-Type": [ "application/json" ], "Accept": [ "*/*" ], "x-forgerock-transactionid": [ txId ] }, "body": '{"authId":"'+request.content.session+'","callbacks":[{"type":"TextOutputCallback","output":[{"name":"message","value":"xxx"},{"name":"messageType","value":"0"}],"_id":0},{"type":"PasswordCallback","output":[{"name":"prompt","value":"One Time Password"}],"input":[{"name":"IDToken3","value":"'+request.content.otp+'"}],"_id":1}]}' } try { var postResult = openidm.action("external/rest", "call", postParams); return { _id: txId, valid: postResult.callbacks[0].output[0].value === 'VALID' }; } catch (ex) { return { _id: txId, valid: false }; } } else if (request.method === 'read') { // GET var getParams = { "url": "https://<tenant-name>/am/json/alpha/authenticate?authIndexType=service&authIndexValue="+journey, "method": "POST", "headers": { "Accept-API-Version": [ "resource=2.0, protocol=1.0" ], "Content-Type": [ "application/json" ] } }; var getResult = openidm.action("external/rest", "call", getParams); return { _id: txId, session: getResult.authId, otp: getResult.callbacks[0].output[0].value }; } else if (request.method === 'update') { // PUT return {}; } else if (request.method === 'patch') { return {}; } else if (request.method === 'delete') { return {}; } throw { code: 500, message: 'Unknown error' }; }());
For example:
-
Click Save.
Notice that an example of the URL you are creating is provided under the custom endpoint name. This is the new endpoint that will be exposed, for example,
https://<tenant-name>/openidm/endpoint/otp
.
To run a test request for the custom endpoint:
-
Click the triangle icon () to open the Test tab.
-
Change the method in the test script to
"read"
and click Run.The session data, OTP and user _id are returned in the response, for example:
-
Copy the response (including curly brackets) and update the test script as follows:
- Change the method to
"create"
and add a comma,
. - Add
"content":
and paste the response text.
For example:
{ "request": { "method": "create", "content": { "session": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI…OAvHB3Q_W-XIj4DyUU", "otp": "816581", "_id": "1680709277513-0c373348bd9b11302a56-203808/0" } } }
- Change the method to
-
Click Run to show the validated token.
Conclusion
This use case has demonstrated how you can configure a custom endpoint in Identity Cloud to call a user journey. You can extend this use case further by integrating customer endpoints into your external UIs or system applications.
Additional resources
Documentation
- Custom endpoints
- Create custom endpoints to launch scripts
- Scripting
- Available to scripts in custom endpoints
- MFA: Open Authentication (OATH)
Training: