Step 3. Develop the client app
Integrating your application with PingOne Protect enables you to perform risk evaluations during your customer’s authentication flow.
Add code for the following tasks to fully integrate with PingOne Protect:
Initialize data collection
The earlier you can initialize data collection, the more data it can collect to make a risk evaluation.
Your client application can manually initialize data collection, and must provide the configuration to control the PingOne Signals SDK.
There are three main methods for initializing data collection:
Direct initialization using the Protect interface
The DaVinci Client allows you to initialize data collection directly using the Protect interface. This provides maximum flexibility in how the collection operates.
To directly initialize data collection using the Protect interface, complete these steps:
-
Add a configuration object to your code that defines the property values for data collection.
The available properties are as follows:
-
Android
-
iOS
-
JavaScript
Parameter Description envIDRequired. Your PingOne environment identifier.
For example,
3072206d-c6ce-ch15-m0nd-f87e972c7cc3deviceAttributesToIgnoreOptional. A list of device attributes to ignore when collecting device signals.
For example,
AUDIO_OUTPUT_DEVICESorIS_ACCEPT_COOKIES.isBehavioralDataCollectionWhen
true, collect behavioral data.Default is
true.isConsoleLogEnabledWhen
true, output SDK log messages in the developer console.Default is
false.isLazyMetadataWhen
true, calculate metadata on demand rather than automatically after callingstart.Default is
false.customHostOptional. Specify a custom host for the Protect API, which can be useful in specific deployment scenarios.
Parameter Description envIDRequired. Your PingOne environment identifier.
For example,
3072206d-c6ce-ch15-m0nd-f87e972c7cc3deviceAttributesToIgnoreOptional. A list of device attributes to ignore when collecting device signals.
For example,
AUDIO_OUTPUT_DEVICESorIS_ACCEPT_COOKIES.isBehavioralDataCollectionWhen
true, collect behavioral data.Default is
true.isConsoleLogEnabledWhen
true, output SDK log messages in the developer console.Default is
false.isLazyMetadataWhen
true, calculate metadata on demand rather than automatically after callingstart.Default is
false.customHostOptional. Specify a custom host for the Protect API, which can be useful in specific deployment scenarios.
Parameter Description envIDRequired. Your PingOne environment identifier.
For example,
3072206d-c6ce-ch15-m0nd-f87e972c7cc3deviceAttributesToIgnoreOptional. A list of device attributes to ignore when collecting device signals.
For example,
AUDIO_OUTPUT_DEVICESorIS_ACCEPT_COOKIES.behavioralDataCollectionWhen
true, collect behavioral data.Default is
true.hubUrlOptional. The iframe URL to use for cross-storage device IDs.
disableHubWhen
true, the client stores device data in the browser’slocalStorageonly.When
falsethe client uses an iframe.Default is
false.disableTagsWhen
true, the client does not collect tag data.Tags are used to record the pages the user visited, forming a browsing history.
Default is
false.externalIdentifiersOptional. A list of custom identifiers that are associated with the device entity in PingOne Protect.
waitForWindowLoadWhen
true, initialize the SDK on theloadevent, instead of theDOMContentLoadedevent.Default is
true.universalDeviceIdentificationOptional. When
true, device data in the payload returned to the server is provided as a signed JWT.Example code:
-
Android
-
iOS
-
JavaScript
Protect.config { isBehavioralDataCollection = true isLazyMetadata = true envId = "3072206d-c6ce-ch15-m0nd-f87e972c7cc3" deviceAttributesToIgnore = listOf("deviceId", "androidId", "serialNumber") isConsoleLogEnabled = true }await Protect.config { protectConfig in protectConfig.isBehavioralDataCollection = true protectConfig.isLazyMetadata = true protectConfig.envId = "3072206d-c6ce-ch15-m0nd-f87e972c7cc3" protectConfig.deviceAttributesToIgnore = ["deviceId", "serialNumber"] protectConfig.isConsoleLogEnabled = true }const protectApi = protect({ behavioralDataCollection: true, envId: "3072206d-c6ce-ch15-m0nd-f87e972c7cc3", deviceAttributesToIgnore: ['deviceId', 'serialNumber'], }); -
-
Call an initialize function to start the data collection using the configuration object:
-
Android
-
iOS
-
JavaScript
Protect.init() Log.d("Protect", "Protect data collection initialized.")try await Protect.initialize() print("Protect data collection initialized.")await protectApi.start(); console.log('Protect data collection initialized.'); -
Use the ProtectLifecycle module for Android or iOS
The DaVinci Client for Android and iOS provide the ProtectLifecycle module for simplifying the management of data collection.
As a DaVinci Client module, it is aware of the current state of authentication, and can automatically pause and resume behavioral data collection when required.
Configure the ProtectLifecycle module in your DaVinci Client configuration, as with other modules.
The available properties are as follows:
| Parameter | Description |
|---|---|
|
Required. Your PingOne environment identifier. For example, |
|
Optional. A list of device attributes to ignore when collecting device signals. For example, |
|
When Default is |
|
When Default is |
|
When Default is |
|
Optional. Specify a custom host for the Protect API, which can be useful in specific deployment scenarios. |
|
When Default is |
|
When |
Example code:
-
Android
-
iOS
DaVinci {
timeout = 30
module(Oidc) {
clientId = "dummy"
// ... Other OIDC configuration
}
module(ProtectLifecycle) {
isBehavioralDataCollection = true
isLazyMetadata = true
envId = "3072206d-c6ce-ch15-m0nd-f87e972c7cc3"
deviceAttributesToIgnore = listOf("deviceId")
isConsoleLogEnabled = true
pauseBehavioralDataOnSuccess = true
resumeBehavioralDataOnStart = true
}
}
let davinci = DaVinci.createDaVinci { config in
config.module(OidcModule.config) { oidcValue in
oidcValue.clientId = "dummy"
// ... Other OIDC configuration
}
config.module(ProtectLifecycleModule.config) { protectValue in
protectValue.isBehavioralDataCollection = true
protectValue.isLazyMetadata = true
protectValue.envId = "3072206d-c6ce-ch15-m0nd-f87e972c7cc3"
protectValue.deviceAttributesToIgnore = ["deviceId"]
protectValue.isConsoleLogEnabled = true
protectValue.pauseBehavioralDataOnSuccess = true
protectValue.resumeBehavioralDataOnStart = true
}
}
On-demand initialization on receipt of ProtectCollector
You can choose not to initialize data collection on app startup and instead initialize it on-demand, when your DaVinci flow reaches the relevant node.
The DaVinci for Android and iOS will automatically initialize data collection when calling the collect() method in response to receiving a ProtectCollector from PingOne. Learn more in Return captured data to a DaVinci flow.
In the DaVinci Client for JavaScript, you can use the start() method to initialize data collection in response to receiving a ProtectCollector from PingOne:
const collectors = davinciClient.getCollectors();
collectors.forEach((collector) => {
if (collector.type === 'ProtectCollector') {
// Optionally use configuration options from the flow to initialize the protect module
const config = collector.output.config;
// Initialize the Protect module and begin collecting data
const protectApi = protect({
envId: '3072206d-c6ce-ch15-m0nd-f87e972c7cc3',
behavioralDataCollection: config.behavioralDataCollection,
universalDeviceIdentification: config.universalDeviceIdentification,
});
await protectApi.start();
}
});
|
Use the |
Pause and resume behavioral data capture
Part of the data collection includes collecting behavioral data, such as how the user interacts with the app, to help when performing evaluations.
There are scenarios where you might want to manually pause the collection of behavioral data.
For example, the user might not be interacting with the app, or you only want to use device attribute data to be considered when performing PingOne Protect evaluations. You can then resume behavioral data collection when required.
The SDKs provide the pauseBehavioralData() and resumeBehavioralData() methods for manually pausing and resuming the capture of behavioral data:
-
Android
-
iOS
-
JavaScript
Protect.pauseBehavioralData() // Pause data collection.
Protect.resumeBehavioralData() // Resume data collection.
await Protect.pauseBehavioralData() // Pause data collection.
await Protect.resumeBehavioralData() // Resume data collection.
await protectApi.pauseBehavioralData() // Pause data collection.
await protectApi.resumeBehavioralData() // Resume data collection.
Return captured data to a DaVinci flow
To perform risk evaluations, the PingOne server requires the captured data.
On receipt of ProtectCollector your app should gather the collected data, update the collector, and call next() to return the collected data to PingOne:
-
Android
-
iOS
-
JavaScript
On receipt of ProtectCollector, use the collect() method to populate the response with the captured data.
When the data is successfully collected, call node.next() to submit the data back to the server for evaluation.
node.collectors.forEach {
when (it) {
is ProtectCollector -> {
when (val result = it.collect()) {
is Success -> {
// Data collection successful: Proceed to the next node in the DaVinci flow.
node.next()
}
is Failure -> {
// Data collection failed: Implement robust error handling.
// Example: Log the error, display an informative message, or implement a retry mechanism.
}
}
}
// ... Handle other collector types
}
}
On receipt of a ProtectCollector callback, use the collect() method to populate the response with the captured data.
When the data is successfully collected, call node.next() to submit the data back to the server for evaluation.
node.collectors.forEach { collector in
switch collector {
case let protectCollector as ProtectCollector:
let result = await protectCollector.collect()
switch result {
case .success:
// Data collection successful: Proceed to the next node in the DaVinci flow.
node.next()
case .failure:
// Data collection failed: Implement robust error handling.
// Example: Log the error, display an informative message, or implement a retry mechanism.
break
}
// ... Handle other collector types
default:
break
}
}
On receipt of a ProtectCollector callback, use the getData() method to prepare the collected data, and call the update() method populate the response with that captured data.
When the data is successfully collected, call next() to submit the data back to the server for evaluation.
async function onSubmitHandler() {
try {
const protectCollector = collectors.find((collector) => collector.type === 'ProtectCollector');
// Update the Protect collector with the data collected
if (protectCollector) {
const updater = davinciClient.update(protectCollector);
const data = await protectApi.getData();
updater(data);
}
// Submit all collectors and get the next node in the flow
await davinciClient.next();
} catch (err) {
// handle error
}
}