Orchestration quickstart: iOS SDK
This guide describes how to quickly integrate Identity Orchestration journeys into your iOS application.
Introduction
The Orchestration SDK enables client-side developers to build user experiences that interact with Client SDK journeys.
Each journey contains a business workflow, such as login or secure user onboarding. It consists of backend steps, such as data processing or invoking external systems, and client-facing steps, such as a login form or document verification. The SDK allows the client application to present screens and prompt for user input, and then send this information back to the journey for further processing.
Whenever the client-side interaction requires additional Mosaic platform capabilities, such as passkeys or risk detection, the developer needs to activate the appropriate SDK module to perform the step and collect the required input. This allows separation of concerns between the journey workflow handling, and the specific capability used.
This guide will use the "Hello World" journey template and instruct you how to build a client side application that works with it. Here is a short video that describes this journey, and how a sample web application interacts with it
Before you start
Before the SDK can start running journeys, make sure to:
-
Create a journey for this tutorial. In the admin portal, go to the
Orchestration
section,
Identity journeys
. From there click on
Templates
, and choose the
Level 0 tutorials / Hello world
template. Click to create a journey from this template. Set the name to
hello-world-quickstart
-
Create an application and obtain the auto-generated Client ID as defined
here
-
Allow Mosaic IPs and
domains
on your network
-
Extend the
Content-Security-Policy
header, if CSP is enabled on your web server
Step 1: Load SDK
The Mosaic iOS SDK is broken down into several modules that can be consumed using Swift Package Manager or Cocoa pods. The Mosaic Identity Orchestration SDK is available here.
-
To use
Swift Package Manager
: install the SDK as a dependency in your
Package.swift
. -
To use
CocoaPods
: specify the SDK in your
Podfile
.
dependencies: [
.package(url: "https://github.com/TransmitSecurity/identityOrchestration-ios-sdk.git", .upToNextMajor(from: "1.0.0"))
]
pod 'IdentityOrchestration', '~> 1.0.1'
Step 2: Initialize SDK
Initializing the SDK configures it to work with your client ID, which is the context under which the entire journey is executed. It also allows setting the base URL for the SDK to use, whether a Mosaic-provided path or your own proxy.
Initialize using PLIST configuration (recommended)
This is a more standardized initialization process that also allows the initialization of multiple SDKs in a consistent manner. To do this, create a plist file named TransmitSecurity.plist
in your Application with the format described below and add this file to your iOS project.
Here's an example of the plist file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>credentials</key>
<dict>
<key>baseUrl</key>
<string>[BASE_URL]</string> <!--Default is https://api.transmitsecurity.io.-->
<key>clientId</key>
<string>[CLIENT_ID]</string>
</dict>
</dict>
</plist>
Here's an example of SDK initialization. You also need to set your app as a delegate to be able to process server responses in an async manner:
do {
try TSIdo.initializeSDK()
TSIdo.delegate = self // Allows to process server responses in async manner
} catch {
debugPrint("[DEBUG]: \(error)")
}
Note
Make sure to add import IdentityOrchestration
at the top of the implementation class.
Initialize using SDK parameters
To do this, configure the SDK using the snippet below:
TSIdo.initialize(
clientId: Env.clientId,
options: .init(serverPath: Env.baseUrl)
)
Note
Make sure to add import IdentityOrchestration
at the top of the implementation class.
Step 3: Start journey
Starting a journey is usually a response to some user interaction, such as clicking a login or sign-up button. Your application should present a button and call the below on user click. Note we use the name we provided for the journey we created from the template:
let idoResponse = TSIdo.startJourney(journeyId: "hello-world-quickstart")
Step 4: Handle service response
After starting the journey, the client app waits for the IdoServiceResponse
. It will contain all the information the client needs in order to determine what to do next.
To handle the service response, the client app needs to:
- Select a handler based on the step
- Implement the hello world form handler
- Implement the display information step handler
1. Select handler
Upon receiving the IdoServiceResponse
, launch a handler that executes the relevant step by switching/selecting on the IdoServiceResponse.journeyStepId
parameter. In the hello-world-quickstart
journey we created, there are two steps that we will have to handle:
-
A
Get Information from Client
step. This step expects the client side to collect some data and send back. The step is configured with the Step ID property set to
.custom(hello_world_form)
. This will be the value of thejourneyStepId
attribute. -
A
Display Information
step that sends presentable text based data collected from the first step. This will have a fixed ID, so the value of the
journeyStepId
is.information
. - Add handlers for Success and Rejection completions
extension ViewController: TSIdoDelegate {
func TSIdoDidReceiveResult(_ result: Result<IdentityOrchestration.TSIdoServiceResponse, IdentityOrchestration.TSIdoJourneyError>) {
switch result {
case .success(let response):
handleJourneyActionUI(for: response)
case .failure(let error):
// Handle error
}
}
}
Each handler will process the data, display whatever UI is needed, and call submitClientResponse()
when the interaction is concluded, more on this in the next sections. This is how the app code would dispatch the above handlers:
private func handleJourneyActionUI(for response: IdentityOrchestration.TSIdoServiceResponse) {
guard let responseStepId = response.journeyStepId else { debugPrint("[DEBUG] No step id found in response"); return }
guard let actionData = response.data else { debugPrint("[DEBUG] No data found in response object"); return }
switch responseStepId {
case .information:
// Show information screen
case .custom("hello_world_form"):
// handle the form with the ID hello_world_form
default:
debugPrint("[DEBUG] Unsupported step: \(responseStepId)")
}
}
2. Implement the Hello World form handler
The following handler is used to get information from the user as described in Get Information from Client step documentation. Specifically, the Hello world form handler should allow the user to enter two strings that should be sent back as username
and password
. This matches the expected schema as you can see in the journey's Get Information from Client step, under Schema field configuration:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"username": {
"type": "string"
},
"password": {
"type": "string",
"format": "password"
}
}
}
You need to display a form that collects these fields, and on user submit sent back to the orchestration service as demonstrated below. Note the response type .clientInput
is standard for almost all journey steps:
// display form to user and collect the required values
let data = [ // compose data that matches the expected schema
"username": collectedUserName,
"password": collectedPassword
]
let idoResponse = TSIdentityOrchestration.submitClientResponse(
clientResponseOptionId: .clientInput,
data: data
)
NOTE
The resulting idoResponse
should be looped back to the handler selection code described in the select handler section above. This response, in our example, will contain the data for displaying the information screen as discussed in the next section.
3. Implement the Display Information handler
The Display Information step is used to display an information screen, as described in the Display Information step guide.
Your handler code should show a screen that displays the information sent from the server, using the data
property provided in the idoServiceResponse
object. The specific structure of the data that will be sent for this step is described below, as well as in the step guide. Note that in our journey, the text
attribute will contain data collected from the user in the previous step:
{
"data": {
"title": "Collected client information",
"text": "Here is what we got from the client side: {...}",
"button_text": "OK"
}
}
The above data is exposed and used as seen here:
// The actionData is taken from the IdoServiceResponse object
let actionData = response.data
let title = actionData["title"] as? [String: any]
let text = actionData["text"] as? [String: any]
let buttonText = actionData["button_text"] as? [String: any]
// display UI based the above, and on button click call the the below
let idoResponse = TSIdentityOrchestration.submitClientResponse(
clientResponseOptionId: .clientInput // no data is sent back
)
NOTE
The resulting idoResponse
should be looped back to the handler selection code described in the select handler section above. This response, in our example, will contain successful completion as described in the next section.
Step 5: Complete journey
The orchestration service signals journey completion by setting the journeyStepId
property to .rejection
or .success
. The specific enum for each SDK is described in the select handler above. In our journey we expect a successful response. The idoServoceResponse.token
property contains a JWT token as a proof of journey completion.
Next steps
You can now proceed to read the in-depth iOS SDK guide