PingOrchestrate
Overview
PingOrchestrate provides a simple way to build a state machine for ForgeRock Journey and PingOne DaVinci.
It allows you to define a series of states and transitions between them. You can use the workflow engine to build
complex workflows that involve multiple steps and conditions.
The Workflow engine allows you to define a series of functions and register them as a module to the Workflow instance
in different state of the workflow.
The Workflow engine contains the following states:

| State | Description | Input | Output | Use Case |
|---|---|---|---|---|
| Init | Initialize the modules | () | Void | OAuth module loads endpoint from discovery URL |
| Start | Start the flow | Request | Request | Intercept the start request, for example inject forceAuth parameter |
| Response | Handle the response | Response | Void | Parse the response, for example store the cookie header. |
| *Transform | Transform the response to Node | Response | Node | For Journey, transform response to Callback, for DaVinci transform to Form |
| Node | Process the Node or Transform the Node | Node | Node | Transform MetadataCallback to WebAuthnCallback |
| Next | Move to next state | Request | Request | Inject noSession parameter |
| Success | Flow finished with Success | Success | Success | Prepare Success with AuthCode or Session |
| SignOff | SignOff the Workflow | Request | Request | Revoke Token and end session |
Module
Module allows you to register functions in different state of the workflow. For example, you can register a function that will be called when the workflow is initialized, when a node is received, when a node is sent, and when the workflow is started.

Information can be shared across state, there are 2 contexts
| Context | Scope | Access |
|---|---|---|
| WorkflowContext | Workflow Instance | context["name"] = "value" |
| FlowContext | Flow from Start to Finish (Success) | flowContext["name"]= "value" |
Integrating the SDK into your project
Use Cocoapods or Swift Package Manager
Usage
To use the Workflow class, you need to create an instance of it by passing a configuration block to the createWorkflow method. The
configuration block allows you to register various modules of the Workflow instance.
Here’s an example of how to create a Workflow instance:
let workflow = Workflow.createWorkflow { config in
config.module(forceAuth)
config.module(noSession)
config.module(session)
}
_ = await workflow.start()
The start method returns a Node instance. The Node class represents the current state of the application. You can
use the next method to transition to the next state.
SignOff
There is a special state called SignOff that is used to sign off the user. You can use the signOff method to sign off
the user.
_ = await workflow.signOff()
Custom Module
You can provide a custom module to the Workflow instance. A module is a class that uses the Module interface.
The Module interface allows the module to install functions in different states during the Workflow flow.
let customHeader = Module.of({ CustomHeaderConfig1() }, setup: { setup in
let config = setup.config
// Intercept all send request and inject custom header
setup.next { ( context, _, request) in
if config.enable {
request.header(name: config.headerName, value: config.headerValue)
}
return request
}
})
You can then install the custom module in the Workflow configuration block like this:
let workflow = Workflow.createWorkflow { config in
config.module(customHeader) { header in
header.headerName = "iOS-SDK2"
header.headerValue = "headervalue3"
}
}
More module examples:
let nosession = Module.of { setup in
//Intercept all send request and inject custom header during start state
setup.next { ( context,_, request) in
request.header(name: "nosession", value: "true")
return request
}
}
let forceAuth = Module.of { setup in
//Intercept all send request and inject custom header during start state
setup.start { ( context, request) in
request.header(name: "forceAuth", value: "true")
return request
}
}
View on GitHub