Ping SDKs

DaVinci Client for DaVinci Flows

Introducing the DaVinci client for DaVinci flows

Server support:

  • PingOne

  • PingOne Advanced Identity Cloud

  • PingAM

  • PingFederate

SDK support:

  • Ping SDK for Android

  • Ping SDK for iOS

  • Ping SDK for JavaScript

The DaVinci clients provide powerful orchestration capabilities with PingOne DaVinci. They enable you to consume DaVinci flows to meet your use cases, all while providing a native Android or iOS, or a single-page app JavaScript experience.

You have complete control of your UI, so you can create the tailored experience you desire for your end users, all while leaving the DaVinci client to do the heavy lifting of communication between your app and your DaVinci flows.

UI Development

You are in charge of the experience your end users have in your Android, iOS, or JavaScript (SPA) applications.

Theme and brand your app the way you want to, focusing on your application logic and letting the DaVinci client communicate with PingOne DaVinci.

Dynamically Updating of DaVinci Flows

The DaVinci client works with PingOne DaVinci server-driven orchestration. This means that as long as you don’t hardcode UI elements in your application, and you appropriately handle the collector types, then you can update your DaVinci flow without needing to update your app or redeploy to the app stores.

Your app responds to changes in your DaVinci flows, without redeploying.
Figure 1. Your app responds to changes in your DaVinci flows, without redeploying.

This saves time and enables you to control your application orchestration experience without unnecessary burden.

Flow collectors

DaVinci sends requests to the DaVinci client from UI-related connectors. This enables you to step through each piece of information, and gather information from your end users appropriately.

Step through flows and and collect input from your users.
Figure 2. Step through flows and and collect input from your users.

For example, if you created a DaVinci flow to register a user, and you used the HTTP Connector - Custom HTML Template capability:

  • First name, last name, and email address would be sent as the TextCollector type to your app, and you would determine the way in which you represented this field in your UI.

  • The password field would be sent as the PasswordCollector type.

  • Once the flow completes, PingOne sends back the necessary tokens, and the DaVinci client automatically stores, retrieves, and refreshes tokens as needed.

Token Management

The DaVinci client uses the OAuth 2.0 auth code flow, and support PKCE.

This method is the best practice for first-party applications. The SDK automatically handles token exchange for you, and also securely stores the tokens.

The DaVinci client handles token refresh automatically, so you don’t have to think about it.

Compatibility

Supported operating systems and browsers

Select a platform below to view the supported operating systems and browsers.

  • Android

  • iOS

  • JavaScript / Login Widget

The Ping SDK for Android supports the following versions of the Android operating system:

Supported Android versions and original release dates
Release API Levels Released

Android 15

35

September, 2024

Android 14

34

October, 2023

Android 13

33

March, 2022

Android 12

31, 32

October, 2021

Android 11

30

September, 2020

Android 10

29

September, 2019

Android 9 (Pie)

28

August, 2018

We are updating how we determine which Android versions form our support policy for the Ping SDK for Android.

From March 1st, 2025, the support policy is as follows:

  • Every public major release of Android within the last 6 years.

    For example, this would mean support for Android 9 (API level 28) and later versions.

Supported browsers on Android

  • Chrome - Two most recent major versions.

The Ping SDK for iOS supports the following versions of the iOS operating system:

Supported iOS versions and original release dates
Release Released

iOS 18

September, 2024

iOS 17

September, 2023

iOS 16

September, 2022

We are updating how we determine which iOS versions form our support policy for the Ping SDK for iOS.

From March 1st, 2025, the support policy is as follows:

  • Every public major release of iOS within the last 3 years.

    For example, this would mean support for iOS 16 and later versions.

Supported browsers on iOS

  • Safari - Two most recent major versions.

The Ping SDK for JavaScript, and the Ping (ForgeRock) Login Widget support the desktop and mobile browsers listed below.

Minimum supported Desktop browser versions

  • Chrome 83

  • Firefox 77

  • Safari 13

  • Microsoft Edge 83 (Chromium)

Supported Mobile browsers

  • iOS (Safari) - Two most recent major versions of the operating system.

  • Android (Chrome) - Two most recent major versions of the operating system.

Supported PingOne fields and collectors

The DaVinci clients support the following connectors and capabilities:

  • PingOne Forms Connector

    • Show Form capability

  • HTTP Connector

    • Custom HTML capability

  • PingOne Form Connector fields

  • HTTP Connector fields

Custom Fields support

Field (Collector)

Description

DaVinci module

Android

iOS

JavaScript

Text Input

(TextCollector)

Collects a single text string.

1.1.0

1.1.0

1.1.0

Password

(PasswordCollector)

Collects a single text string that cannot be read from the screen.

1.1.0

1.1.0

1.1.0

Dropdown

(SingleSelectCollector)

Collects a value from a dropdown containing one or more text strings.

1.1.0

1.1.0

1.1.0

Combobox

(MultiSelectCollector)

Collects a value from a dropdown containing one or more text strings, the user can enter their own text string.

1.1.0

1.1.0

1.1.0

Radio Button List

(SingleSelectCollector)

Collects a value from one or radio buttons.

1.1.0

1.1.0

1.1.0

Checkbox List

(MultiSelectCollector)

Collects the value of one or more checkboxes.

1.1.0

1.1.0

1.1.0

Toolbox support

Field (Collector)

Description

DaVinci module

Android

iOS

JavaScript

Flow Button

(FlowCollector)

Presents a customized button.

1.1.0

1.1.0

1.1.0

Flow Link

(FlowCollector)

Presents a customized link.

1.1.0

1.1.0

1.1.0

Translatable Rich Text

(TextCollector)

Presents rich text that you can translate into multiple languages.

1.1.0

1.1.0

1.1.0

Social Login

(IdpCollector)

Presents a button to allow users to authenticate using an external identity provider, such as Apple, Facebook, or Google.

1.1.0

1.1.0

1.1.0

HTTP Connector field and collector support

Field (Collector)

Description

DaVinci module

Android

iOS

JavaScript

Text field

(TextCollector)

Collects a single text string.

1.0.0

1.0.0

1.0.0

Password field

(PasswordCollector)

Collects a single text string that cannot be read from the screen.

1.0.0

1.0.0

1.0.0

Submit Button

(SubmitCollector)

Sends the collected data to PingOne to continue the DaVinci flow.

1.0.0

1.0.0

1.0.0

Flow Button

(FlowCollector)

Triggers an alternative flow without sending the data collected so far to PingOne.

1.0.0

1.0.0

1.0.0

Label

(LabelCollector)

Display a read-only text label.

1.1.0

1.1.0

1.1.0

Radio / Dropdown

(SingleSelectCollector)

Collects a single value from a choice of multiple options.

1.1.0

1.1.0

1.1.0

HTTP Connector SK-Component support

SK-Component (Collector)

Description

DaVinci module

Android

iOS

JavaScript

skIDP

(IdpCollector)

Presents a button to allow users to authenticate using an external identity provider, such as Apple, Facebook, or Google.

1.1.0

1.1.0

1.1.0

Unsupported features:

Verify that your flow does not depend on any unsupported elements:

SKPolling components

SKPolling components cannot be processed by the SDK and should not be included.

Images

Images included in the flow cannot be passed to the SDK.

Default DaVinci client headers

Applies to:

  • DaVinci client for Android

  • DaVinci client for iOS

  • DaVinci client for JavaScript

The DaVinci clients send a number of header values to the server with every outgoing request.

These headers can help you identify the client in your flows and help you correlate actions to a transaction in DaVinci audit logs. You can also use these values to alter the course of a DaVinci flow.

The default headers the DaVinci client always include are as follows:

x-requested-with

Identifies that the request comes from an app built with the Ping DaVinci client.

Default value: ping-sdk

x-requested-platform

Identifies the platform the DaVinci client is running on.

Default values:

Platform Value

Android

android

iOS

ios

JavaScript

javascript

interactionId

Returns the interactionId value provided by the server to help trace the transaction in server audit logs and dashboards.

Example value: 18484499-c551-4d99-c415-b01c79bedb47

interactionToken

Returns the interactionToken value provided by the server to help trace the transaction in server audit logs and dashboards.

Example value: 437783552aa3a5a8f0041028d5b8dac2d72f7e7ebd7f88a966fb690402f6571b964c3df8897cbe542e62721070b3f6fcc946f4dd2bc80b9df332d39657fcaaad4651884093a786910d6f1337bd8dda17b4fca48e8fa481469ce0df1f676e46d1a6fc30577d910010d4a2530f2d02e69f436d610992c79fcb0ca87131d0df3f9a

Getting started with the DaVinci client

Applies to:

  • DaVinci client for Android

  • DaVinci client for iOS

  • DaVinci client for JavaScript

Discover how to get started with the DaVinci client, including the following topics:

Installing the DaVinci client

Learn how to install the DaVinci client for Android, iOS, and JavaScript, as well as any dependencies your platform might require.

Stepping through DaVinci flows

DaVinci sends requests to the DaVinci client from UI-related connectors. Learn how to step through each node in the flow and gather information from your end users appropriately.

Leverage UI toolkits

You are in charge of the experience your end users have in your applications. You can leverage UI tool kits such as Jetpack Compose for Android or SwiftUI for iOS to help create the necessary user interface for your mobile apps.

Getting started with the DaVinci client for Android

Applies to:

  • DaVinci client for Android

  • DaVinci client for iOS

  • DaVinci client for JavaScript

Configure DaVinci client for Android properties to connect to PingOne and step through an associated DaVinci flow.

Installing and importing the DaVinci client

To use the DaVinci client for Android, add the relevant dependencies to your project:

  1. In the Project tree view of your Android Studio project, open the Gradle Scripts/build.gradle.kts file for the DaVinci module.

  2. In the dependencies section, add the following:

    implementation("com.pingidentity.sdks:davinci:1.1.0")
    Example of the dependencies section after editing:
    dependencies {
    
        val composeBom = platform(libs.androidx.compose.bom)
        implementation(composeBom)
    
        // DaVinci client
        implementation("com.pingidentity.sdks:davinci:1.1.0")
    
        ...
    
        implementation(libs.androidx.core.ktx)
        implementation(libs.androidx.appcompat)
        implementation(libs.material)
    }

Configuring the DaVinci client

Configure DaVinci client for Android properties to connect to PingOne and step through an associated DaVinci flow.

The following shows an example DaVinci client configuration, using the underlying Oidc module:

Configure DaVinci client connection properties
import com.pingidentity.davinci.DaVinci
import com.pingidentity.davinci.module.Oidc

val daVinci = DaVinci {
    module(Oidc) {
        clientId = "6c7eb89a-66e9-ab12-cd34-eeaf795650b2"
        discoveryEndpoint = "https://auth.pingone.com/3072206d-c6ce-ch15-m0nd-f87e972c7cc3/" +
            "as/.well-known/openid-configuration"
        scopes = mutableSetOf("openid", "profile", "email", "address", "revoke")
        redirectUri = "org.forgerock.demo://oauth2redirect"
        additionalParameters = mapOf("customKey" to "customValue")
    }
}

For information on the properties available, refer to Configure DaVinci client for Android properties.

Stepping through DaVinci flows

To authenticate your users the DaVinci client for Android must start the flow, and step through each node.

For information on which connectors and fields the DaVinci client supports, refer to Compatibility.

Starting a DaVinci flow

To start a DaVinci flow, call the start() method:

Start a DaVinci flow
val node = daVinci.start()

Determining DaVinci flow node type

Each step of the flow returns one of four node types:

ContinueNode

This type indicates there is input required from the client. The node object for this type contains a collector object, which describes the information it requires from the client.

SuccessNode

This type indicates the flow is complete, and authentication was successful.

ErrorNode

This type indicates an error in the data sent to the server. For example, an email address in an incorrect format, or a password that does not meet complexity requirements.

You can correct the error and resubmit to continue the flow.

FailureNode

This type indicates that the flow could not be completed and must be restarted. This can be caused by a server error, or a timeout.

You can use the helper functions to determine which node type the server has returned:

Determine node type.
when (node) {
    is ContinueNode -> {}
    is ErrorNode -> {}
    is FailureNode -> {}
    is SuccessNode -> {}
}

Handling DaVinci flow collectors in continue nodes

The ContinueNode type contains collectors. These collectors define what information or action to request from the user, or client device.

There are specific collector types. For example there are TextCollector and PasswordCollector types.

To complete a DaVinci flow we recommend that you implement a component for each connector type you will encounter in the flow. Then you can iterate through the flow and handle each collector as you encounter it.

Access collectors in a ContinueNode
node.collectors.forEach {
    when(it) {
        is TextCollector → it.value = "My First Name"
        is PasswordCollector → it.value = "My Password"
        is SubmitCollector → it.value = "click me"
        is FlowCollector → it.value = "Forgot Password"
    }
}

Continuing a DaVinci flow

After collecting the data for a node you can proceed to the next node in the flow by calling the next() method on your current node object.

Continue a DaVinci flow using next()
val next = node.next()

You do not need to pass any parameters into the next method as the DaVinci client internally stores the updated object, ready to return to the PingOne server.

The server responds with a new node object, just like when starting a flow initially.

Loop again through conditional checks on the new node’s type to render the appropriate UI or take the appropriate action.

Handling DaVinci flow error nodes

DaVinci flows return the ErrorNode type when it receives data that is incorrect, but you can fix the data and resubmit. For example, an email value submitted in an invalid format or a new password that is too short.

You can retrieve the error message by using node.message(), and the raw JSON response with node.input.

Displaying the reason for an error
val node = daVinci.start() // Start the flow

//Determine the Node Type
when (node) {
    is ContinueNode -> {}
    is ErrorNode -> {
        node.message() // Retrieve the cause of the error
    }
    is FailureNode -> {}
    is SuccessNode -> {}
}

This is different than a FailureNode type, which you cannot resubmit and must restart the entire flow.

You can retain a reference to the node you submit in case the next node you receive is an ErrorNode type. If so, you can re-render the previous form, and inject the error information from the new ErrorNode node.

After the user revises the data call next() as you did before.

Handling DaVinci flow failure nodes

DaVinci flows return the FailureNode type if there has been an issue that prevents the flow from continuing. For example, the flow times out or suffers a server error.

You can retrieve the cause of the failure by using node.cause(), which is a Throwable object.

Handling receipt of a FailureNode type
val node = daVinci.start() // Start the flow

//Determine the Node Type
when (node) {
    is ContinueNode -> {}
    is ErrorNode -> {}
    is FailureNode -> {
        node.cause() // Retrieve the error message
    }
    is SuccessNode -> {}
}

You should offer to restart the flow on receipt of a FailureNode type.

Handling DaVinci flow success nodes

DaVinci flows return the SuccessNode type when the user completes the flow and PingOne issues them a session.

To retrieve the existing session, you can use the following code:

Handling receipt of a SuccessNode type
val user: User? = daVinci.user()

user?.let {
    it.accessToken()
    it.revoke()
    it.userinfo()
    it.logout()
}

Leverage Jetpack Compose

The following shows how you could use the DaVinci client with Jetpack Compose:

ViewModel
// Define State that listen by the View
var state = MutableStateFlow<Node>(Empty)

//Start the DaVinci flow
val next = daVinci.start()

// Update the state
state.update {
    next
}

fun next(node: ContinueNode) {
    viewModelScope.launch {
        val next = node.next()
        state.update {
            next
        }
    }
}
View
when (val node = state.node) {
    is ContinueNode -> {}
    is ErrorNode -> {}
    is FailureNode -> {}
    is SuccessNode -> {}
}

Getting started with the DaVinci client for iOS

Applies to:

  • DaVinci client for Android

  • DaVinci client for iOS

  • DaVinci client for JavaScript

Configure DaVinci client module for iOS properties to connect to PingOne and step through an associated DaVinci flow.

Installing and importing the DaVinci client

To use the DaVinci client for iOS, use Swift Package Manager (SPM) to add the dependencies to your project:

You can install this by using SPM (Swift Package Manager) on the generated iOS project.

  1. In Xcode, select your project and navigate to Package Dependencies.

  2. Click the sign, and add the Ping SDK for iOS repository, https://github.com/ForgeRock/forgerock-ios-sdk.git.

  3. Add the davinci library to the project.

Configuring the DaVinci client

Configure DaVinci client for iOS properties to connect to PingOne and step through an associated DaVinci flow.

The following shows an example DaVinci client configuration, using the underlying Oidc module:

Configure DaVinci client connection properties
let daVinci = DaVinci.createDaVinci { config in
    // Oidc as module
    config.module(OidcModule.config) { oidcValue in
        oidcValue.clientId = "6c7eb89a-66e9-ab12-cd34-eeaf795650b2"
        oidcValue.discoveryEndpoint = "https://auth.pingone.com/3072206d-c6ce-ch15-m0nd-f87e972c7cc3/as/.well-known/openid-configuration"
        oidcValue.scopes = ["openid", "profile", "email", "address", "revoke"]
        oidcValue.redirectUri = "org.forgerock.demo://oauth2redirect"
        oidcValue.additionalParameters = ["customKey":"customValue"]
    }
}

For information on the properties available, refer to Configure DaVinci client for iOS properties.

Stepping through DaVinci flows

To authenticate your users the DaVinci client for iOS must start the flow, and step through each node.

For information on which connectors and fields the DaVinci client supports, refer to Compatibility.

Starting a DaVinci flow

To start a DaVinci flow, call the start() method:

Start a DaVinci flow
var node = await daVinci.start()

Determining DaVinci flow node type

Each step of the flow returns one of four node types:

ContinueNode

This type indicates there is input required from the client. The node object for this type contains a collector object, which describes the information it requires from the client.

SuccessNode

This type indicates the flow is complete, and authentication was successful.

ErrorNode

This type indicates an error in the data sent to the server. For example, an email address in an incorrect format, or a password that does not meet complexity requirements.

You can correct the error and resubmit to continue the flow.

FailureNode

This type indicates that the flow could not be completed and must be restarted. This can be caused by a server error, or a timeout.

You can use the helper functions to determine which node type the server has returned:

Determine node type.
switch (node) {
  case is ContinueNode: do {}
  case is ErrorNode: do {}
  case is FailureNode: do {}
  case is SuccessNode: do {}
}

Handling DaVinci flow collectors in continue nodes

The ContinueNode type contains collectors. These collectors define what information or action to request from the user, or client device.

There are specific collector types. For example there are TextCollector and PasswordCollector types.

To complete a DaVinci flow we recommend that you implement a component for each connector type you will encounter in the flow. Then you can iterate through the flow and handle each collector as you encounter it.

Access collectors in a ContinueNode
node.collectors.forEach { item in
    switch(item) {
    case is TextCollector:
        (item as! TextCollector).value = "My First Name"
    case is PasswordCollector:
        (item as! PasswordCollector).value = "My Password"
    case is SubmitCollector:
        (item as! SubmitCollector).value = "click me"
    case is FlowCollector:
        (item as! FlowCollector).value = "Forgot Password"
    }
}

Continuing a DaVinci flow

After collecting the data for a node you can proceed to the next node in the flow by calling the next() method on your current node object.

Continue a DaVinci flow using next()
let next = node.next()

You do not need to pass any parameters into the next method as the DaVinci client internally stores the updated object, ready to return to the PingOne server.

The server responds with a new node object, just like when starting a flow initially.

Loop again through conditional checks on the new node’s type to render the appropriate UI or take the appropriate action.

Handling DaVinci flow error nodes

DaVinci flows return the ErrorNode type when it receives data that is incorrect, but you can fix the data and resubmit. For example, an email value submitted in an invalid format or a new password that is too short.

You can retrieve the error message by using node.message(), and the raw JSON response with node.input.

Displaying the reason for an error
let node = await daVinci.start() //Start the flow

//Determine the Node Type
switch (node) {
  case is ContinueNode: do {}
  case is FailureNode: do {}
  case is ErrorNode:
      (node as! ErrorNode).message //Retrieve the error message
  case is SuccessNode: do {}
}

This is different than a FailureNode type, which you cannot resubmit and must restart the entire flow.

You can retain a reference to the node you submit in case the next node you receive is an ErrorNode type. If so, you can re-render the previous form, and inject the error information from the new ErrorNode node.

After the user revises the data call next() as you did before.

Handling DaVinci flow failure nodes

DaVinci flows return the FailureNode type if there has been an issue that prevents the flow from continuing. For example, the flow times out or suffers a server error.

You can retrieve the cause of the failure by using node.cause(), which is an Error instance.

Handling receipt of a FailureNode type
let node = await daVinci.start() //Start the flow

//Determine the Node Type
switch (node) {
  case is ContinueNode: do {}
  case is FailureNode:
    (node as! FailureNode).cause //Retrieve the cause of the Failure
  case is ErrorNode: do {}
  case is SuccessNode: do {}
}

You should offer to restart the flow on receipt of a FailureNode type.

Handling DaVinci flow success nodes

DaVinci flows return the SuccessNode type when the user completes the flow and PingOne issues them a session.

To retrieve the existing session, you can use the following code:

Handling receipt of a SuccessNode type
let user: User? = await daVinci.user()

_ = await user?.token()
await user?.revoke()
_ = await user?.userinfo(cache: false)
await user?.logout()

Leverage SwiftUI

The following shows how you could use the DaVinci client with SwiftUI:

ViewModel
//Define State that listen by the View

@Published var state: Node = EmptyNode()

//Start the DaVinci flow
let next = await daVinci.start()

//Update the state
state = next

func next(node: ContinueNode) {
   val next = await node.next()
   state = next

}
View
if let node = state.node {
    switch node {
    case is ContinueNode:
        // Handle ContinueNode case
        break
    case is ErrorNode:
        // Handle Error case
        break
    case is FailureNode:
        // Handle Failure case
        break
    case is SuccessNode:
        // Handle Success case
        break
    default:
        break
    }
}

Getting started with the DaVinci client for JavaScript

Applies to:

  • DaVinci client for Android

  • DaVinci client for iOS

  • DaVinci client for JavaScript

Configure DaVinci client properties to connect to PingOne and step through an associated DaVinci flow.

Installing and importing the DaVinci client

To install and import the DaVinci client:

  1. Install the DaVinci client into your JavaScript apps using npm:

    Install the DaVinci client
    npm install @forgerock/davinci-client
  2. Import the DaVinci client as a named import:

    Import the DaVinci client
    import { davinci } from '@forgerock/davinci-client';

Configuring the DaVinci client

Configure DaVinci client for JavaScript properties to connect to PingOne and step through an associated DaVinci flow.

The following shows a full DaVinci client configuration:

Configure DaVinci client connection properties
import { davinci } from '@forgerock/davinci';

const davinciClient = await davinci({
  config: {
    clientId: '6c7eb89a-66e9-ab12-cd34-eeaf795650b2',
    serverConfig: {
      wellknown: 'https://auth.pingone.com/3072206d-c6ce-ch15-m0nd-f87e972c7cc3/as/.well-known/openid-configuration',
      timeout: 3000,
    },
    scope: 'openid profile email address revoke',
    responseType: 'code',
  },
});

For information on the properties available, refer to Configure DaVinci client for JavaScript properties.

Stepping through DaVinci flows

To authenticate your users the Ping SDK for JavaScript DaVinci client must start the flow, and step through each node.

For information on which connectors and fields the DaVinci client supports, refer to Compatibility.

Starting a DaVinci flow

To start a DaVinci flow, call the start() method on your new client object:

Start a DaVinci flow
let node = await davinciClient.start();
Adding custom parameters

When starting a DaVinci client you can add additional key-pair parameters. The DaVinci client will append these parameters as query strings to the initial OAuth 2.0 call to the /authorize endpoint.

You can access these additional OAuth 2.0 parameters in your DaVinci flows by using the authorizationRequest.<customParameter> property.

To add parameters when starting the client, create an object of the key-value pairs and pass it as a query parameter to the start() function:

const query = {
  customKey: 'customValue'
}

let node = await davinciClient.start(query);

You can add any parameters to the request as required. For example, you could add acr_values to the request to the /authorize endpoint.

Determining DaVinci flow node type

Each step of the flow returns one of four node types:

continue

This type indicates there is input required from the client. The node object for this type contains a list of collector objects, which describe the information it requires from the client.

success

This type indicates the flow is complete, and authentication was successful.

error

This type indicates an error in the data sent to the server. For example, an email address in an incorrect format, or a password that does not meet complexity requirements.

You can correct the error and resubmit to continue the flow.

failure

This type indicates that the flow could not be completed and must be restarted. This can be caused by a server error, or a timeout.

Use node.status to determine which node type the server has returned:

Determine node type using the node.status property
let node = await davinciClient.start();

switch (node.status) {
  case 'continue':
    return renderContinue();
  case 'success':
    return renderSuccess();
  case 'error':
    return renderError();
  default: // Handle 'failure' node type
    return renderFailure();
}

Handling DaVinci flow collectors in continue nodes

The continue node type contains a list of collector objects. These collectors define what information or action to request from the user, or browser.

There are two categories of collector:

SingleValueCollector

A request for a single value, such as a username or password string.

Show the interface for SingleValueCollector
export interface SingleValueCollector {
  category: 'SingleValueCollector';
  type: SingleValueCollectorTypes;
  id: string;
  name: string;
  input: {
    key: string;
    value: string | number | boolean;
    type: string;
  };
  output: {
    key: string;
    label: string;
    type: string;
    value: string;
  };
}
ActionCollector

Represents an action the user can take, such as a button or a link they can select. For example, a link that jumps to a password recovery section of a flow.

Show the interface for ActionCollector
export interface ActionCollector {
  category: 'ActionCollector';
  type: ActionCollectorTypes;
  id: string;
  name: string;
  output: {
    key: string;
    label: string;
    type: string;
    url?: string;
  };
}

Within each category of collector there are specific collector types. For example, in the SingleValueCollector category there are TextCollector and PasswordCollector types.

To complete a DaVinci flow we recommend that you implement a component for each connector type you will encounter in the flow. Then you can iterate through the flow and handle each collector as you encounter it.

Example 1. TextCollector

This example shows how to update a collector with a value gathered from your user.

Pass both a collector and updater object into a component that renders the appropriate user interface, captures the user’s input, and then updates the collector, ready to return to the server.

Example TextCollector mapping
const collectors = davinciClient.getCollectors();
collectors.map((collector) => {
  if (collector.type === 'TextCollector') {
    renderTextCollector(collector, davinciClient.update(collector));
  }
});

Mutating the node object, the collectors array, or any other properties does not alter the internal state of the DaVinci client.

The internal data the client stores is immutable and can only be updated using the provided APIs, not through property assignment.

Your renderTextCollector would resemble the following:

Example TextCollector updater component
function renderTextCollector(collector, updater) {
  // ... component logic

  function onClick(event) {
    updater(event.target.value);
  }

  // render code
}
Example 2. FlowCollector

This example shows how change from the current flow to an alternate flow, such as a reset password or registration flow.

To switch flows, call the flow method on the davinciClient passing the key property to identify the new flow.

Example FlowCollector mapping
const collectors = davinciClient.getCollectors();
collectors.map((collector) => {
  if (collector.type === 'FlowCollector') {
    renderFlowCollector(collector, davinciClient.flow(collector));
  }
});

This returns a function you can call when the user interacts with it.

Example flowCollector component
function renderFlowCollector(collector, startFlow) {
  // ... component logic

  function onClick(event) {
    startFlow();
  }

  // render code
}
Example 3. SubmitCollector

This example shows how submit the current node and its collected values back to the server. The collection of the data is already complete so an updater component is not required. This collector only renders the button for the user to submit the collected data.

Example SubmitCollector mapping
const collectors = davinciClient.getCollectors();
collectors.map((collector) => {
  if (collector.type === 'SubmitCollector') {
    renderSubmitCollector(
      collector, // This is the only argument you will need to pass
    );
  }
});

Continuing a DaVinci flow

After collecting the data for a node you can proceed to the next node in the flow by calling the next() method on your DaVinci client object.

This can be the result of a user clicking on the button rendered from the SubmitCollector, from the submit event of an HTML form, or by programmatically triggering the submission in the application layer.

Continue a DaVinci flow using next()
let nextStep = davinciClient.next();

You do not need to pass any parameters into the next method as the DaVinci client internally stores the updated object, ready to return to the PingOne server.

The server responds with a new node object, just like when starting a flow initially.

Loop again through conditional checks on the new node’s type to render the appropriate UI or take the appropriate action.

Handling DaVinci flow error nodes

DaVinci flows return the error node type when it receives data that is incorrect, but you can fix the data and resubmit. For example, an email value submitted in an invalid format or a new password that is too short.

This is different than a failure node type which you cannot resubmit and instead you must restart the entire flow.

You can retain a reference to the node you submit in case the next node you receive is an error type. If so, you can re-render the previous form, and inject the error information from the new error node.

After the user revises the data call next() as you did before.

Handling DaVinci flow failure nodes

DaVinci flows return the failure node type if there has been an issue that prevents the flow from continuing. For example, the flow times out or suffers an HTTP 500 server error.

You should offer to restart the flow on receipt of a failure node type.

Restart a DaVinci flow on receipt of a failure node type
const node = await davinciClient.next();

if (node.status === 'failure') {
  const error = davinciClient.getError();
  renderError(error);

  // ... user clicks button to restart flow
  const freshNode = davinciClient.start();
}

Handling DaVinci flow success nodes

DaVinci flows return the success node type when the user completes the flow and PingOne issues them a session.

On receipt of a success node type you should use the OAuth 2.0 authorization Code and state properties from the node and use them to obtain an access token on behalf of the user.

To obtain an access token, leverage the Ping SDK for JavaScript.

Example of obtaining an access token using the Ping SDK for JavaScript
// ... other imports
import { davinci } from '@forgerock/davinci-client';
import { Config, TokenManager } from '@forgerock/javascript-sdk';

// ... other config or initialization code

// This Config.set accepts the same config schema as the davinci function
Config.set(config);

const node = await davinciClient.next();

if (node.status === 'success') {
  const clientInfo = davinciClient.getClient();

  const code = clientInfo.authorization?.code || '';
  const state = clientInfo.authorization?.state || '';

  const tokens = await TokenManager.getTokens({
    query: {
      code, state
    }
  });

  // user now has session and OIDC tokens
}

Configure DaVinci client properties

Applies to:

  • DaVinci client for Android

  • DaVinci client for iOS

  • DaVinci client for JavaScript

The Ping SDKs are designed to be flexible and can be customized to suit many different situations.

Learn more about configuring and customizing the Ping SDKs in the sections below:

Configure DaVinci client properties

Learn how to configure properties in the DaVinci clients so they can connect to your authorization server to authenticate your users and obtain tokens.

Localize DaVinci client UI

Learn how you can leverage the languages feature in PingOne to localize your client applications for different audiences.

Configure DaVinci client properties

Applies to:

  • DaVinci client for Android

  • DaVinci client for iOS

  • DaVinci client for JavaScript

You need to configure certain settings so that the DaVinci client can connect to your PingOne instance to step through your DaVinci flows and authenticate your users.

The method you use to configure these settings depends on which platform you are using.

Configure DaVinci client for Android properties

Applies to:

  • DaVinci client for Android

  • DaVinci client for iOS

  • DaVinci client for JavaScript

Configure DaVinci client for Android properties to connect to PingOne and step through an associated DaVinci flow.

Create an instance of the DaVinci object and use the underlying Oidc module to set configuration properties.

The following properties are available for configuring the DaVinci client for Android:

Properties
Property Description Required?

discoveryEndpoint

Your PingOne server’s .well-known/openid-configuration endpoint.

Example:

https://auth.pingone.com/3072206d-c6ce-ch15-m0nd-f87e972c7cc3/as/.well-known/openid-configuration

Yes

clientId

The client_id of the OAuth 2.0 client profile to use.

For example, 6c7eb89a-66e9-ab12-cd34-eeaf795650b2

Yes

scopes

A set of scopes to request when performing an OAuth 2.0 authorization flow.

For example, "openid", "profile", "email", "address", "revoke".

Yes

redirectUri

The redirect_uri as configured in the OAuth 2.0 client profile.

This value must match a value configured in your OAuth 2.0 client.

For example, org.forgerock.demo://oauth2redirect.

Yes

timeout

A timeout, in seconds, for each request that communicates with the server.

Default is 30 seconds.

No

acrValues

Request which flow the PingOne server uses by adding an Authentication Context Class Reference (ACR) parameter.

Enter a single DaVinci policy by using its flow policy ID.

Example:

"d1210a6b0b2665dbaa5b652221badba2"

No

additionalParameters

Add additional key-pair parameters as query strings to the initial OAuth 2.0 call to the /authorize endpoint.

For example, additionalParameters = mapOf("customKey" to "customValue")

You can access these additional OAuth 2.0 parameters in your DaVinci flows by using the authorizationRequest.<customParameter> property.

No

Example

The following shows an example DaVinci client configuration, using the underlying Oidc module:

Configure DaVinci client connection properties
import com.pingidentity.davinci.DaVinci
import com.pingidentity.davinci.module.Oidc

val daVinci = DaVinci {
    module(Oidc) {
        clientId = "6c7eb89a-66e9-ab12-cd34-eeaf795650b2"
        discoveryEndpoint = "https://auth.pingone.com/3072206d-c6ce-ch15-m0nd-f87e972c7cc3/" +
            "as/.well-known/openid-configuration"
        scopes = mutableSetOf("openid", "profile", "email", "address", "revoke")
        redirectUri = "org.forgerock.demo://oauth2redirect"
        additionalParameters = mapOf("customKey" to "customValue")
    }
}

Configure DaVinci client for iOS properties

Applies to:

  • DaVinci client for Android

  • DaVinci client for iOS

  • DaVinci client for JavaScript

Configure DaVinci client module for iOS properties to connect to PingOne and step through an associated DaVinci flow.

Create an instance of the DaVinci class by passing configuration to the createDaVinci method. This uses the underlying Oidc module to set configuration properties.

The following properties are available for configuring the DaVinci client for iOS:

Properties
Property Description Required?

discoveryEndpoint

Your PingOne server’s .well-known/openid-configuration endpoint.

Example:

https://auth.pingone.com/3072206d-c6ce-ch15-m0nd-f87e972c7cc3/as/.well-known/openid-configuration

Yes

clientId

The client_id of the OAuth 2.0 client profile to use.

For example, 6c7eb89a-66e9-ab12-cd34-eeaf795650b2

Yes

scopes

A set of scopes to request when performing an OAuth 2.0 authorization flow.

For example, "openid", "profile", "email", "address", "revoke".

Yes

redirectUri

The redirect_uri as configured in the OAuth 2.0 client profile.

This value must match a value configured in your OAuth 2.0 client.

For example, org.forgerock.demo://oauth2redirect.

Yes

timeout

A timeout, in seconds, for each request that communicates with the server.

Default is 30 seconds.

No

acrValues

Request which flow the PingOne server uses by adding an Authentication Context Class Reference (ACR) parameter.

Enter a single DaVinci policy by using its flow policy ID.

Example:

"d1210a6b0b2665dbaa5b652221badba2"

No

additionalParameters

Add additional key-pair parameters as query strings to the initial OAuth 2.0 call to the /authorize endpoint.

For example, myConfig.additionalParameters = ["customKey":"customValue"]

You can access these additional OAuth 2.0 parameters in your DaVinci flows by using the authorizationRequest.<customParameter> property.

No

Example

The following shows an example DaVinci client configuration, using the underlying Oidc module:

Configure DaVinci client connection properties
let daVinci = DaVinci.createDaVinci { config in
    // Oidc as module
    config.module(OidcModule.config) { oidcValue in
        oidcValue.clientId = "6c7eb89a-66e9-ab12-cd34-eeaf795650b2"
        oidcValue.discoveryEndpoint = "https://auth.pingone.com/3072206d-c6ce-ch15-m0nd-f87e972c7cc3/as/.well-known/openid-configuration"
        oidcValue.scopes = ["openid", "profile", "email", "address", "revoke"]
        oidcValue.redirectUri = "org.forgerock.demo://oauth2redirect"
        oidcValue.additionalParameters = ["customKey":"customValue"]
    }
}

Configure DaVinci client for JavaScript properties

Applies to:

  • DaVinci client for Android

  • DaVinci client for iOS

  • DaVinci client for JavaScript

Configure DaVinci client properties to connect to PingOne and step through an associated DaVinci flow.

Pass a config object into davinci to initialize a client with the required connection properties.

The following properties are available for configuring the DaVinci client for JavaScript:

Properties
Property Description Required?

serverConfig

An interface for configuring how the SDK contacts the PingAM instance.

Contains wellknown and timeout.

Yes

serverConfig: {wellknown}

Your PingOne server’s .well-known/openid-configuration endpoint.

Example:

https://auth.pingone.com/3072206d-c6ce-ch15-m0nd-f87e972c7cc3/as/.well-known/openid-configuration

Yes

serverConfig: {timeout}

A timeout, in milliseconds, for each request that communicates with your server.

For example, for 30 seconds specify 30000.

Defaults to 5000 (5 seconds).

No

clientId

The client_id of the OAuth 2.0 client profile to use.

For example, 6c7eb89a-66e9-ab12-cd34-eeaf795650b2

Yes

scope

A list of scopes to request when performing an OAuth 2.0 authorization flow, separated by spaces.

For example, openid profile email address revoke.

No

responseType

The type of OAuth 2.0 flow to use, either code or token.

Defaults to code.

No

Example

The following shows a full DaVinci client configuration:

Configure DaVinci client connection properties
import { davinci } from '@forgerock/davinci';

const davinciClient = await davinci({
  config: {
    clientId: '6c7eb89a-66e9-ab12-cd34-eeaf795650b2',
    serverConfig: {
      wellknown: 'https://auth.pingone.com/3072206d-c6ce-ch15-m0nd-f87e972c7cc3/as/.well-known/openid-configuration',
      timeout: 3000,
    },
    scope: 'openid profile email address revoke',
    responseType: 'code',
  },
});

Localizing the user interface

Applies to:

  • DaVinci client for Android

  • DaVinci client for iOS

  • DaVinci client for JavaScript

You can leverage the languages feature in PingOne to localize your client applications for different audiences.

The DaVinci clients automatically send the preferred languages configured in the browser or mobile device to PingOne so that it can return the appropriate language.

Console output from an iOS client showing Accept-Language header
[Ping SDK 1.1.0] ⬆
Request URL: https://auth.pingone.com/c2a6...1602/as/authorize?response_mode=pi.flow&client_id=85ff...6791&response_type=code&scope=openid&redirect_uri=http://localhost:5829&code_challenge=m8BD...rhPM&code_challenge_method=S256
Request Method: GET
Request Headers: [
    "x-requested-platform": "ios",
    "Content-Type": "application/json",
    "x-requested-with": "ping-sdk",
    "Accept-Language": "en-GB, en;q=0.9"
]
Request Timeout: 15.0

You can also override the configured settings directly in your code if required.

Before you begin

You must configure PingOne to support multiple languages that your client apps can use:

  1. In PingOne, enable the built-in languages you want to support.

    You can also add your own languages and regions.

    Learn more in Adding a language.

  2. Ensure your language has the required localized strings for your clients to use.

    You can also add your own keys to a language for use in your client applications.

  3. Add your localized strings to your chosen implementation:

    PingOne forms

    Update the fields in your PingOne forms to use translatable keys.

    Adding localized strings to a PingOne form.
    Figure 3. Adding localized strings to a PingOne form

    Learn more in Using translatable keys.

    Custom HTTP Connector

    Update the Output Fields in your custom HTML to use your localized strings.

    Adding localized strings to a custom HTTP connector

    Adding localized strings to a custom HTTP connector.

    Learn more in HTTP Connector.

Configuring a DaVinci client to send the language header

The DaVinci clients automatically send the Accept-Language header when making requests to the PingOne server. This header includes each of the languages configured on the client device or in the browser, and maintains the order of preference.

The DaVinci client for Android and iOS also add generic versions of sub-dialects configured on the device, to make it more likely that PingOne can fall back to a similar language if the specific sub-dialect is unavailable.

For example, configuring English (British) (en-GB) as a preferred languages causes the DaVinci client to also send English (en) as a fallback option:

"Accept-Language": "en-GB, en;q=0.9"

Overriding the automatically-added languages

You can override the default behavior of automatically sending configured languages.

  • DaVinci client for Android

  • DaVinci client for iOS

  • DaVinci client for JavaScript

To provide your own values for the Accept-Language header, use the CustomHeader module.

Add the module to your DaVinci configuration as follows:

Using the CustomHeader module to override default language behavior
import com.pingidentity.davinci.DaVinci
import com.pingidentity.davinci.module.Oidc
import com.pingidentity.davinci.module.CustomHeader

val daVinci = DaVinci {
    module(Oidc) {
        clientId = "6c7eb89a-66e9-ab12-cd34-eeaf795650b2"
        discoveryEndpoint = "https://auth.pingone.com/3072206d-c6ce-ch15-m0nd-f87e972c7cc3/as/.well-known/openid-configuration"
        scopes = mutableSetOf("openid", "profile", "email", "address", "revoke")
        redirectUri = "org.forgerock.demo://oauth2redirect"
        additionalParameters = mapOf("customKey" to "customValue")
    }

    // Add French as the preferred language, before default options
    module(CustomHeader, priority = 5, mode = OverrideMode.APPEND) {
        header(name = "Accept-Language", value = "fr")
    }
}
priority

Default behavior of the DaVinci client is provided by a number of built-in modules. These modules all run with a priority value of 10.

  • To run your module before the default modules ensure your module has a priority value less than the default of 10.

  • To run your module after the default modules, set the prioriy value to greater than 10.

mode

You can choose how the CustomHeader module applies the modification by using the mode parameter:

OverrideMode.APPEND

The DaVinci client combines any additional parameters you provide with any parameters the default behavior adds.

The order is determined by the priority order of the modules.

OverrideMode.OVERRIDE

Any additional parameters you provide replace any parameters the default behavior would have added.

To provide your own values for the Accept-Language header, use the CustomHeader module.

Add the module to your DaVinci configuration as follows:

Using the CustomHeader module to override default language behavior
import PingDavinci

public let davinci = DaVinci.createDaVinci { config in
    let currentConfig = ConfigurationManager.shared.currentConfigurationViewModel
    config.module(OidcModule.config) { oidcValue in
        oidcValue.clientId = "6c7eb89a-66e9-ab12-cd34-eeaf795650b2"
        oidcValue.scopes = ["openid", "profile", "email", "address", "revoke"]
        oidcValue.redirectUri = "org.forgerock.demo://oauth2redirect"
        oidcValue.discoveryEndpoint = "https://auth.pingone.com/3072206d-c6ce-ch15-m0nd-f87e972c7cc3/as/.well-known/openid-configuration"
    }

    // Add French as the preferred language, before default options
    config.module(CustomHeader.config, priority: 5, mode: .append) { customHeaderValue in
        customHeaderValue.header(name: "Accept-Language", value: "fr")
    }
}
priority

Default behavior of the DaVinci client is provided by a number of built-in modules. These modules all run with a priority value of 10.

  • To run your module before the default modules ensure your module has a priority value less than the default of 10.

  • To run your module after the default modules, set the prioriy value to greater than 10.

mode

You can choose how the CustomHeader module applies the modification by using the mode parameter:

.append

The DaVinci client combines any additional parameters you provide with any parameters the default behavior adds.

The order is determined by the priority order of the modules.

.override

Any additional parameters you provide replace any parameters the default behavior would have added.

To override the default browser behavior and provide your own values for the Accept-Language header, use the RequestMiddleware type.

Call your request middleware when creating the DaVinci client as follows:

Using the CustomHeader module to override default language behavior
import { davinci } from '@forgerock/davinci';
import type { RequestMiddleware } from '@forgerock/davinci-client/types';

const requestMiddleware: RequestMiddleware[] = [
  (fetchArgs, action, next) => {
    fetchArgs.headers?.set('Accept-Language', 'fr-FR, fr;q=0.9');
    next();
  },
];

const davinciClient = await davinci({
  config: {
    clientId: '6c7eb89a-66e9-ab12-cd34-eeaf795650b2',
    serverConfig: {
      wellknown: 'https://auth.pingone.com/3072206d-c6ce-ch15-m0nd-f87e972c7cc3/as/.well-known/openid-configuration',
      timeout: 3000,
    },
    scope: 'openid profile email address revoke',
    responseType: 'code',
  },
  requestMiddleware
});

Ping SDK for PingOne DaVinci tutorials

These tutorials walk you through updating a provided sample app so that it connects to a PingOne tenant to authenticate a user using a DaVinci flow, such as the PingOne sign-on with sessions flow.

This flow allows users to register, authenticate, and verify their email address with PingOne. It combines the PingOne Sign On and Password Reset flow, which allows users to reset or recover their passwords, with the PingOne Registration and Email Verification flow, which allows users to register and verify their email. In addition, this flow checks for an active user session before prompting for authentication.

Features of the PingOne sign-on with sessions flow
Figure 4. Overview of the PingOne sign-on with sessions flow

The tutorials also support DaVinci flows that use the PingOne Forms connector.

Each tutorial provides a list of the supported capabilities and fields.

Check that your flows use only supported fields before attempting to use them with the Ping SDKs.

You will implement code that:

  • Configures the app with the connection settings for your PingOne instance.

  • Starts a DaVinci flow

  • Renders UI depending on the type of node encountered in the flow

  • Returns responses to each node encountered

  • Gets an access token for the user on completion of the flow

  • Gets the user’s details from PingOne, such as their full name and email address

  • Logs the user out of PingOne

To start, choose the platform to host your app:

DaVinci flow tutorial for Android


This tutorial walks you through updating a provided sample app so that it connects to a PingOne tenant to authenticate a user using the PingOne sign-on with sessions DaVinci flow.

This flow allows users to register, authenticate, and verify their email address with PingOne.

Before you begin

Before you begin this tutorial ensure you have set up your PingOne server with the required configuration.

For example, you will need to have an OAuth 2.0 client application set up.

Step 1. Download the samples

To start this tutorial, you need to download the SDK sample apps repo, which contains the projects you will use.

Step 2. Configure the sample app

In this step, you configure the sample app to connect to the OAuth 2.0 application you created in DaVinci.

Step 3. Test the app

To test the app, run the sample that you configured in the previous step.

The sample connects to your PingOne server to obtain the correct URIs to authenticate the user, and redirects the browser to your PingOne server.

After authentication, PingOne redirects the browser back to your application, which then obtains an OAuth 2.0 access token and displays the related user information.

Before you begin


To successfully complete this tutorial refer to the prerequisites in this section.

The tutorial also requires a configured PingOne instance.

Compatibility

PingOne
  • Your PingOne instance must have DaVinci enabled.

DaVinci flows

Ensure your flows only use supported connectors, capabilities and fields for user interactions:

  • HTTP Connector

    • Custom HTML capability

      View supported fields
      HTTP Connector field and collector support

      Field (Collector)

      Description

      DaVinci module

      Android

      iOS

      JavaScript

      Text field

      (TextCollector)

      Collects a single text string.

      1.0.0

      1.0.0

      1.0.0

      Password field

      (PasswordCollector)

      Collects a single text string that cannot be read from the screen.

      1.0.0

      1.0.0

      1.0.0

      Submit Button

      (SubmitCollector)

      Sends the collected data to PingOne to continue the DaVinci flow.

      1.0.0

      1.0.0

      1.0.0

      Flow Button

      (FlowCollector)

      Triggers an alternative flow without sending the data collected so far to PingOne.

      1.0.0

      1.0.0

      1.0.0

      Label

      (LabelCollector)

      Display a read-only text label.

      1.1.0

      1.1.0

      1.1.0

      Radio / Dropdown

      (SingleSelectCollector)

      Collects a single value from a choice of multiple options.

      1.1.0

      1.1.0

      1.1.0

      HTTP Connector SK-Component support

      SK-Component (Collector)

      Description

      DaVinci module

      Android

      iOS

      JavaScript

      skIDP

      (IdpCollector)

      Presents a button to allow users to authenticate using an external identity provider, such as Apple, Facebook, or Google.

      1.1.0

      1.1.0

      1.1.0

      View unsupported features

      Verify that your flow does not depend on any unsupported elements:

      SKPolling components

      SKPolling components cannot be processed by the SDK and should not be included.

      Images

      Images included in the flow cannot be passed to the SDK.

  • PingOne Form Connector

    • Show Form capability

      View supported fields
      Custom Fields support

      Field (Collector)

      Description

      DaVinci module

      Android

      iOS

      JavaScript

      Text Input

      (TextCollector)

      Collects a single text string.

      1.1.0

      1.1.0

      1.1.0

      Password

      (PasswordCollector)

      Collects a single text string that cannot be read from the screen.

      1.1.0

      1.1.0

      1.1.0

      Dropdown

      (SingleSelectCollector)

      Collects a value from a dropdown containing one or more text strings.

      1.1.0

      1.1.0

      1.1.0

      Combobox

      (MultiSelectCollector)

      Collects a value from a dropdown containing one or more text strings, the user can enter their own text string.

      1.1.0

      1.1.0

      1.1.0

      Radio Button List

      (SingleSelectCollector)

      Collects a value from one or radio buttons.

      1.1.0

      1.1.0

      1.1.0

      Checkbox List

      (MultiSelectCollector)

      Collects the value of one or more checkboxes.

      1.1.0

      1.1.0

      1.1.0

      Toolbox support

      Field (Collector)

      Description

      DaVinci module

      Android

      iOS

      JavaScript

      Flow Button

      (FlowCollector)

      Presents a customized button.

      1.1.0

      1.1.0

      1.1.0

      Flow Link

      (FlowCollector)

      Presents a customized link.

      1.1.0

      1.1.0

      1.1.0

      Translatable Rich Text

      (TextCollector)

      Presents rich text that you can translate into multiple languages.

      1.1.0

      1.1.0

      1.1.0

      Social Login

      (IdpCollector)

      Presents a button to allow users to authenticate using an external identity provider, such as Apple, Facebook, or Google.

      1.1.0

      1.1.0

      1.1.0

Android

This sample requires at least Android API 23 (Android 6.0)

Java

This sample requires at least Java 8 (v1.8).

Prerequisites

Android Studio

Download and install Android Studio, which is available for many popular operating systems.

An Android emulator or physical device

To try the quick start application as you develop it, you need an Android device. To add a virtual, emulated Android device to Android Studio, refer to Create and manage virtual devices, on the Android Developers website.

Server configuration

You must configure your PingOne instance for use with the DaVinci client.

Ask your PingOne administrator to complete the following tasks:

  • Configure a DaVinci flow

  • Create a DaVinci application

  • Configure PingOne for DaVinci flow invocation

To learn how to complete these steps, refer to Launching a flow with a Ping SDK in the PingOne DaVinci documentation.

Step 1. Download the samples


To start this tutorial, you need to download the ForgeRock SDK sample apps repo, which contains the projects you will use.

  1. In a web browser, navigate to the SDK Sample Apps repository.

  2. Download the source code using one of the following methods:

    Download a ZIP file
    1. Click Code, and then click Download ZIP.

    2. Extract the contents of the downloaded ZIP file to a suitable location.

    Use a Git-compatible tool to clone the repo locally
    1. Click Code, and then copy the HTTPS URL.

    2. Use the URL to clone the repository to a suitable location.

      For example, from the command-line you could run:

The result of these steps is a local folder named sdk-sample-apps.

Step 2. Configure the sample app


In this section you open the sample project in Android Studio, and view the integration points in the TODO pane.

You’ll visit each integration point in the sample app to understand how to complete a DaVinci flow, including handling the different nodes and their collectors, obtaining an access token and user information, and finally signing out of the session.

  1. In Android Studio, click Open, navigate to the sdk-sample-apps/android/kotlin-davinci folder that has the downloaded sample source code in, and then click Open.

    Android Studio opens and loads the DaVinci tutorial project.

  2. In the Project pane, navigate to samples > app.

  3. On the View menu, select Tool Windows, and then click TODO.

    The sample code is annotated with TODO comments to help you locate the integration points, where code changes are required.

    android sample todo pane en
    Figure 5. Integration points annotated with TODO comments
  4. In the TODO pane, double-click the STEP 1 line.

    Android Studio opens DaVinciViewModel.kt:

    DaVinciViewModel.kt
    //TODO: Integration Point. STEP 1
    val daVinci = DaVinci {
        logger = Logger.STANDARD
    
        // Oidc as module
        module(Oidc) {
            clientId = "<Client ID>"
            discoveryEndpoint = "<Discovery Endpoint>"
            scopes = mutableSetOf("<scope1>", "<scope2>", "…​")
            redirectUri = "<Redirect URI>"
        }
    }

    This snippet initializes the DaVinci module, and leverages the OpenID Connect (OIDC) module to configure the settings to connect to your PingOne instance.

    1. Replace <Client ID> with the ID of the client you are connecting to in PingOne.

      Example:

      clientId = "6c7eb89a-66e9-ab12-cd34-eeaf795650b2"

      Refer to Get configuration values from PingOne for instructions of where to find this value.

    2. Replace <Discovery Endpoint> with the OIDC Discovery Endpoint value from the client you are connecting to in PingOne.

      Example:

      discoveryEndpoint = "https://auth.pingone.ca/3072206d-c6ce-ch15-m0nd-f87e972c7cc3/as/.well-known/openid-configuration"

      Refer to Get configuration values from PingOne for instructions of where to find this value.

    3. In the scopes property, add the scopes you want to assign users who complete authentication using the client.

      Example:

      scopes = mutableSetOf("openid", "email", "profile")

    4. Replace <Redirect URI> with the application ID of your sample app, followed by ://oauth2redirect.

      Example:

      redirectUri = "org.forgerock.demo://oauth2redirect"

      The redirectUri value you use must exactly match one of the Redirect URIs value you enter in the native OAuth 2.0 application you created earlier.

    5. Optionally, delete the TODO comment to remove it from the list.

    The result resembles the following:

    DaVinciViewModel.kt
    val daVinci = DaVinci {
        logger = Logger.STANDARD
    
        // Oidc as module
        module(Oidc) {
            clientId = "6c7eb89a-66e9-ab12-cd34-eeaf795650b2"
            discoveryEndpoint = "https://auth.pingone.ca/3072206d-c6ce-ch15-m0nd-f87e972c7cc3/as/.well-known/openid-configuration"
            scopes = mutableSetOf("openid", "email", "profile")
            redirectUri = "org.forgerock.demo://oauth2redirect"
        }
    }
  5. In the TODO pane, double-click the STEP 2 line.

    Android Studio opens DaVinciViewModel.kt:

    DaVinciViewModel.kt
    //TODO: Integration Point. STEP 2
    // Start the DaVinci flow, next node from the flow will be returned
    // Update the state with the next node
    
    /*
    val next = daVinci.start()
    
    state.update {
        it.copy(prev = next, node = next)
    }
    */

    This snippet calls start() to start the DaVinci flow, and assigns the returned node to the variable next.

    It also updates the app’s state to store the response as both prev and node.

    1. Uncomment the highlighted text.

    2. Optionally, delete the TODO comment to remove it from the list.

  6. In the TODO pane, double-click the STEP 3 line.

    Android Studio opens DaVinciViewModel.kt:

    DaVinciViewModel.kt
    //TODO: Integration Point. STEP 3
    // Continue the DaVinci flow, next node from the flow will be returned
    // Update the state with the next node
    
    /*
    val next = current.next()
    
    state.update {
        it.copy(prev = current, node = next)
    }
    */

    This snippet calls next() to continue the DaVinci flow, by proceeding to the next available node. It assigns the newly returned node to the variable next.

    It also updates the app’s state to store the new response as node, and the current node as prev.

    1. Uncomment the highlighted text.

    2. Optionally, delete the TODO comment to remove it from the list.

  7. In the TODO pane, double-click the STEP 4 line.

    Android Studio opens DaVinci.kt:

    DaVinci.kt
    //TODO: Integration Point. STEP 4
    // Render the current node depending on its type
    
    /*
    when (val node = state.node) {
        is ContinueNode → {
            Render(node = node, onNodeUpdated, onStart) { onNext(node) }
        }
        is FailureNode → {
            Log.e("DaVinci", node.cause.message, node.cause)
            Render(node = node)
        }
        is ErrorNode → {
            Render(node)
            // Render the previous node
            if (state.prev is ContinueNode) {
                Render(node = state.prev, onNodeUpdated, onStart) { onNext(state.prev) }
            }
        }
        is SuccessNode → {
            LaunchedEffect(true) { onSuccess?.let { onSuccess() } }
        }
        else → {}
    }
    */

    This snippet watches for a change in state, and takes an action based on the ode type returned by DaVinci.

    For example, if it is a FailureNode log an error message. If the node is a ContinueNode that continues the flow, call the render function to display the necessary fields on the screen.

    1. Uncomment the highlighted text.

    2. Optionally, delete the TODO comment to remove it from the list.

  8. In the TODO pane, double-click the STEP 5 line.

    Android Studio opens ContinueNode.kt:

    ContinueNode.kt
    //TODO: Integration Point. STEP 5
    // Intermediate step in the Davinci Flow. The ContinueNode is a node that is used to
    // continue the flow. It can have multiple collectors that are used to collect user input.
    // Render the UI for each collector that are part of the ContinueNode.
    
    /*
    continueNode.collectors.forEach {
        when (it) {
            is FlowCollector → {
                hasAction = true
                FlowButton(it, onNext)
            }
    
            is PasswordCollector → {
                Password(it, onNodeUpdated)
            }
            is SubmitCollector → {
                hasAction = true
                SubmitButton(it, onNext)
            }
    
            is TextCollector → Text(it, onNodeUpdated)
        }
    }
    */

    This snippet handles the various collectors that are returned by the current node.

    Loop through all of the collectors in the node and render an appropriate field in your app.

    For example, this snippet handles text and password fields, and two types of button, a submit and a flow type.

    1. Uncomment the highlighted text.

    2. Optionally, delete the TODO comment to remove it from the list.

  9. In the TODO pane, double-click the STEP 6 line.

    Android Studio opens TokenViewModel.kt:

    TokenViewModel.kt
    //TODO: Integration Point. STEP 6
    // Retrieve the access token
    
    /*
    User.user()?.let {
       when (val result = it.token()) {
            is Failure → {
                state.update {
                    it.copy(token = null, error = result.value)
                }
            }
    
            is Success → {
                state.update {
                    it.copy(token = result.value, error = null)
                }
            }
        }
    } ?: run {
        state.update {
            it.copy(token = null, error = null)
        }
    }
    */

    This snippet gets called when the flow reaches a SuccessNode and gets an access token on behalf of the authenticated user.

    1. Uncomment the highlighted text.

    2. Optionally, delete the TODO comment to remove it from the list.

  10. In the TODO pane, double-click the STEP 7 line.

    Android Studio opens UserProfileViewModel.kt:

    UserProfileViewModel.kt
    //TODO: Integration Point. STEP 7
    // Retrieve the user info
    
    /*
    User.user()?.let { user →
        when (val result = user.userinfo(false)) {
            is Result.Failure →
                state.update { s →
                    s.copy(user = null, error = result.value)
                }
    
            is Result.Success →
                state.update { s →
                    s.copy(user = result.value, error = null)
                }
        }
    }
    */

    This snippet gets the user’s info from DaVinci, for example their preferred name for display within the sample app.

    1. Uncomment the highlighted text.

    2. Optionally, delete the TODO comment to remove it from the list.

  11. In the TODO pane, double-click the STEP 8 line.

    Android Studio opens LogoutViewModel.kt:

    LogoutViewModel.kt
    //TODO: Integration Point. STEP 8
    // logout the user
    
    /*
    User.user()?.logout()
    */

    This snippet calls the logout() function on the User object to sign the user out of the app, and end their session in DaVinci.

    1. Uncomment the highlighted text.

    2. Optionally, delete the TODO comment to remove it from the list.

Step 3. Test the app


In the following procedure, you run the sample app that you configured in the previous step.

  1. Add or connect a device to Android Studio.

    Learn more about devices in Android Studio in the Android Developer documentation:

  2. On the Run menu, click Run 'samples.app'.

    Android Studio starts the sample application on the simulated or connected device.

    The app automatically starts the DaVinci flow:

    The DaVinci sample app first screen with fields and buttons.
    Figure 6. The DaVinci sample app first screen with fields and buttons.
  3. Optionally, to register a new identity in PingOne, tap the No Account? Register now! link.

    This link is an example of a FlowButton.

    The app displays the registration screen:

    The DaVinci sample app registration screen
    Figure 7. The DaVinci sample app registration screen.
    1. Enter the details of the new identity, and then click Save.

      The app creates the new identity in PingOne and returns to the sign on screen.

  4. Enter the username and password of a PingOne identity, and then click Sign On.

    The app sends the credentials to PingOne for validation, and on success displays the user’s info:

    The DaVinci sample app displaying user info
    Figure 8. The DaVinci sample app displaying user info
  5. Tap the menu () icon, and then tap generating_tokens Show Token.

    The app shows the access token obtained on behalf of the user.

    The DaVinci sample app displaying a user’s access token
    Figure 9. The DaVinci sample app displaying a user’s access token
  6. Tap the menu () icon, and then tap logout Logout.

    The app revokes the existing tokens and ends the session in PingOne.

Troubleshooting

This section contains help if you encounter an issue running the sample code.

What can cause validation errors in the request?

When starting the app you might see an error message as follows:

The request could not be completed. One or more validation errors were in the request.

davinci sample validation error en
Figure 10. Validation error when starting the app

The Logcat pane in Android Studio often contains additional information about the error:

{
  "id" : "2a72bf00-5f20-4b78-a7d0-ad8d95e9b11b",
  "code" : "INVALID_DATA",
  "message" : "The request could not be completed. One or more validation errors were in the request.",
  "details" : [
    {
      "code" : "INVALID_VALUE",
      "target" : "redirect_uri",
      "message" : "Redirect URI mismatch"
    }
  ]
}

In this case the cause is Redirect URI mismatch.

Ensure that your redirectUri value in com/pingidentity/samples/app/davinci/DaVinciViewModel.kt exactly matches one of the values you entered in the Redirect URIs field in your OAuth 2.0 application in PingOne:

.Match the redirect URIs in the sample app and PingOne configuration
Figure 11. Match the redirect URIs in the sample app and PingOne configuration

DaVinci flow tutorial for iOS


This tutorial walks you through updating a provided sample app so that it connects to a PingOne tenant to authenticate a user using the PingOne sign-on with sessions DaVinci flow.

This flow allows users to register, authenticate, and verify their email address with PingOne.

Before you begin

Before you begin this tutorial ensure you have set up your PingOne server with the required configuration.

For example, you will need to have an OAuth 2.0 client application set up.

Step 1. Download the samples

To start this tutorial, you need to download the SDK sample apps repo, which contains the projects you will use.

Step 2. Configure the sample app

In this step, you configure the sample app to connect to the OAuth 2.0 application you created in DaVinci.

Step 3. Test the app

To test the app, run the sample that you configured in the previous step.

The sample connects to your PingOne server to obtain the correct URIs to authenticate the user, and redirects the browser to your PingOne server.

After authentication, PingOne redirects the browser back to your application, which then obtains an OAuth 2.0 access token and displays the related user information.

Before you begin


To successfully complete this tutorial refer to the prerequisites in this section.

The tutorial also requires a configured PingOne instance.

Compatibility

PingOne
  • Your PingOne instance must have DaVinci enabled.

DaVinci flows

Ensure your flows only use supported connectors, capabilities and fields for user interactions:

  • HTTP Connector

    • Custom HTML capability

      View supported fields
      HTTP Connector field and collector support

      Field (Collector)

      Description

      DaVinci module

      Android

      iOS

      JavaScript

      Text field

      (TextCollector)

      Collects a single text string.

      1.0.0

      1.0.0

      1.0.0

      Password field

      (PasswordCollector)

      Collects a single text string that cannot be read from the screen.

      1.0.0

      1.0.0

      1.0.0

      Submit Button

      (SubmitCollector)

      Sends the collected data to PingOne to continue the DaVinci flow.

      1.0.0

      1.0.0

      1.0.0

      Flow Button

      (FlowCollector)

      Triggers an alternative flow without sending the data collected so far to PingOne.

      1.0.0

      1.0.0

      1.0.0

      Label

      (LabelCollector)

      Display a read-only text label.

      1.1.0

      1.1.0

      1.1.0

      Radio / Dropdown

      (SingleSelectCollector)

      Collects a single value from a choice of multiple options.

      1.1.0

      1.1.0

      1.1.0

      HTTP Connector SK-Component support

      SK-Component (Collector)

      Description

      DaVinci module

      Android

      iOS

      JavaScript

      skIDP

      (IdpCollector)

      Presents a button to allow users to authenticate using an external identity provider, such as Apple, Facebook, or Google.

      1.1.0

      1.1.0

      1.1.0

      View unsupported features

      Verify that your flow does not depend on any unsupported elements:

      SKPolling components

      SKPolling components cannot be processed by the SDK and should not be included.

      Images

      Images included in the flow cannot be passed to the SDK.

  • PingOne Form Connector

    • Show Form capability

      View supported fields
      Custom Fields support

      Field (Collector)

      Description

      DaVinci module

      Android

      iOS

      JavaScript

      Text Input

      (TextCollector)

      Collects a single text string.

      1.1.0

      1.1.0

      1.1.0

      Password

      (PasswordCollector)

      Collects a single text string that cannot be read from the screen.

      1.1.0

      1.1.0

      1.1.0

      Dropdown

      (SingleSelectCollector)

      Collects a value from a dropdown containing one or more text strings.

      1.1.0

      1.1.0

      1.1.0

      Combobox

      (MultiSelectCollector)

      Collects a value from a dropdown containing one or more text strings, the user can enter their own text string.

      1.1.0

      1.1.0

      1.1.0

      Radio Button List

      (SingleSelectCollector)

      Collects a value from one or radio buttons.

      1.1.0

      1.1.0

      1.1.0

      Checkbox List

      (MultiSelectCollector)

      Collects the value of one or more checkboxes.

      1.1.0

      1.1.0

      1.1.0

      Toolbox support

      Field (Collector)

      Description

      DaVinci module

      Android

      iOS

      JavaScript

      Flow Button

      (FlowCollector)

      Presents a customized button.

      1.1.0

      1.1.0

      1.1.0

      Flow Link

      (FlowCollector)

      Presents a customized link.

      1.1.0

      1.1.0

      1.1.0

      Translatable Rich Text

      (TextCollector)

      Presents rich text that you can translate into multiple languages.

      1.1.0

      1.1.0

      1.1.0

      Social Login

      (IdpCollector)

      Presents a button to allow users to authenticate using an external identity provider, such as Apple, Facebook, or Google.

      1.1.0

      1.1.0

      1.1.0

iOS

This sample app is compatible with iOS 12 and later.

Prerequisites

Xcode

You can download the latest version for free from https://developer.apple.com/xcode/.

Server configuration

You must configure your PingOne instance for use with the DaVinci client.

Ask your PingOne administrator to complete the following tasks:

  • Configure a DaVinci flow

  • Create a DaVinci application

  • Configure PingOne for DaVinci flow invocation

To learn how to complete these steps, refer to Launching a flow with a Ping SDK in the PingOne DaVinci documentation.

Step 1. Download the samples


To start this tutorial, you need to download the ForgeRock SDK sample apps repo, which contains the projects you will use.

  1. In a web browser, navigate to the SDK Sample Apps repository.

  2. Download the source code using one of the following methods:

    Download a ZIP file
    1. Click Code, and then click Download ZIP.

    2. Extract the contents of the downloaded ZIP file to a suitable location.

    Use a Git-compatible tool to clone the repo locally
    1. Click Code, and then copy the HTTPS URL.

    2. Use the URL to clone the repository to a suitable location.

      For example, from the command-line you could run:

The result of these steps is a local folder named sdk-sample-apps.

Step 2. Configure the sample app


In this section you open the sample project in Xcode, and view the integration points in the TODO pane.

You’ll visit each integration point in the sample app to understand how to complete a DaVinci flow, including handling the different nodes and their collectors, obtaining an access token and user information, and finally signing out of the session.

  1. In Xcode, on the File menu, click Open.

  2. Navigate to the sdk-sample-apps folder you cloned in the previous step, navigate to iOS > swiftui-davinci > Davinci.xcworkspace, and then click Open.

    Xcode opens and loads the DaVinci tutorial project.

  3. Open DavinciViewModel and locate the DaVinci.createDaVinci call:

    The DaVinci.createDaVinci call in DavinciViewModel
    public let davinci = DaVinci.createDaVinci { config in
      //TODO: Provide here the Server configuration. Add the PingOne server Discovery Endpoint and the OAuth 2.0 client details
      config.module(OidcModule.config) { oidcValue in
        oidcValue.clientId = "Client ID"
        oidcValue.scopes = ["scope1", "scope2", "scope3"]
        oidcValue.redirectUri = "Redirect URI"
        oidcValue.discoveryEndpoint = "Discovery Endpoint"
      }
    }

    This snippet initializes the DaVinci module, and leverages the OpenID Connect (OIDC) module to configure the settings to connect to your PingOne instance.

    1. In the oidcValue.clientId property, enter the ID of the client you are connecting to in PingOne.

      Example:

      clientId = "6c7eb89a-66e9-ab12-cd34-eeaf795650b2"

      Refer to Get configuration values from PingOne for instructions of where to find this value.

    2. In the oidcValue.scopes property, add the scopes you want to assign users who complete authentication using the client.

      Example:

      scopes = mutableSetOf("openid", "email", "profile")

    3. In the oidcValue.redirectUri property, enter the application ID of your sample app, followed by ://oauth2redirect.

      Example:

      redirectUri = "org.forgerock.demo://oauth2redirect"

      The redirectUri value you use must exactly match one of the Redirect URIs value you enter in the native OAuth 2.0 application you created earlier.

    4. In the oidcValue.discoveryEndpoint property, enter the OIDC Discovery Endpoint value from the client you are connecting to in PingOne.

      Example:

      discoveryEndpoint = "https://auth.pingone.ca/3072206d-c6ce-ch15-m0nd-f87e972c7cc3/as/.well-known/openid-configuration"

      Refer to Get configuration values from PingOne for instructions of where to find this value.

    5. Optionally, delete the TODO comment to remove it from the list.

    The result resembles the following:

    DavinciViewModel
    public let davinci = DaVinci.createDaVinci { config in
      //TODO: Provide here the Server configuration. Add the PingOne server Discovery Endpoint and the OAuth2.0 client details
      config.module(OidcModule.config) { oidcValue in
        oidcValue.clientId = "6c7eb89a-66e9-ab12-cd34-eeaf795650b2"
        oidcValue.scopes = ["openid", "email", "profile"]
        oidcValue.redirectUri = "org.forgerock.demo://oauth2redirect"
        oidcValue.discoveryEndpoint = "https://auth.pingone.ca/3072206d-c6ce-ch15-m0nd-f87e972c7cc3/as/.well-known/openid-configuration"
      }
    }

Step 3. Test the app


In the following procedure, you run the sample app that you configured in the previous step. The app performs a centralized login on your PingOne instance.

Log in as a demo user

  1. In Xcode, select Product  Run.

    Xcode launches the sample app in the iPhone simulator.

    ios kotlin davinci main menu
    Figure 12. The iOS DaVinci sample main menu
  2. In the sample app on the iPhone simulator, tap Launch Davinci.

    The sample app launches the DaVinci flow configured in the OAuth 2.0 profile.

    ios kotlin davinci login
    Figure 13. The DaVinci sample app first screen with fields and buttons.
  3. Optionally, to register a new identity in PingOne:

    1. Tap the No Account? Register now! link.

      This link is an example of a FlowButton.

      The app displays the registration screen:

      The DaVinci sample app registration screen
      Figure 14. The DaVinci sample app registration screen.
    2. Enter the details of the new identity, and then click Save.

      The app creates the new identity in PingOne and returns to the sign on screen.

  4. Sign on as a demo user:

    • Name: demo

    • Password: Ch4ng3it!

    If authentication is successful, the application displays the tokens issued by PingOne.

    ios kotlin davinci access token
    Figure 15. The token issues by the DaVinci flow
  5. Tap Davinci to go back to the main menu, and then tap User Info.

    The app retrieves the user’s info from the /userinfo endpoint and displays it on screen:

    ios kotlin davinci userinfo
    Figure 16. User info retrieved from PingOne
  6. Tap Davinci to go back to the main menu, and then tap Logout.

    The sample app displays a logout button.

    ios kotlin davinci logout
    Figure 17. Logout button in the iOS sample app
  7. Tap Proceed to logout

    The app revokes the existing tokens and ends the session in PingOne.

    To verify the user is signed out:

    1. In the PingOne administration console, navigate to Directory > Users.

    2. Select the user you signed in as.

    3. From the Sevices dropdown, select Authentication:

      pingone sessions en
      Figure 18. Checking a user’s sessions in PingOne.

      The Sessions section displays any existing sessions the user has, and whether they originate from a mobile device.

DaVinci flow tutorial for JavaScript


This tutorial walks you through updating a provided sample app so that it connects to a PingOne tenant to authenticate a user using the PingOne sign-on with sessions DaVinci flow.

This flow allows users to register, authenticate, and verify their email address with PingOne.

Before you begin

Before you begin this tutorial ensure you have set up your PingOne instance with the required configuration.

For example, you will need an OAuth 2.0 client application set up.

Step 1. Download the samples

To start this tutorial, you need to download the SDK sample apps repo, which contains the projects you will use.

Step 2. Install the dependencies

The sample projects need a number of dependencies that you can install by using the npm command.

For example, the Ping SDK for JavaScript itself is one of the dependencies.

Step 3. Configure connection properties

In this step, you configure the "embedded-login" sample app to connect to the OAuth 2.0 application you created in PingOne Advanced Identity Cloud or PingAM.

Step 4. Test the app

The final step is to run the sample app. The sample connects to your server and walks through your authentication journey or tree.

After successful authentication, the sample obtains an OAuth 2.0 access token and displays the related user information.

Before you begin


To successfully complete this tutorial refer to the prerequisites in this section.

The tutorial also requires a configured server.

Compatibility

PingOne
  • Your PingOne instance must have DaVinci enabled.

DaVinci flows

Ensure your flows only use supported connectors, capabilities and fields for user interactions:

  • HTTP Connector

    • Custom HTML capability

      View supported fields
      HTTP Connector field and collector support

      Field (Collector)

      Description

      DaVinci module

      Android

      iOS

      JavaScript

      Text field

      (TextCollector)

      Collects a single text string.

      1.0.0

      1.0.0

      1.0.0

      Password field

      (PasswordCollector)

      Collects a single text string that cannot be read from the screen.

      1.0.0

      1.0.0

      1.0.0

      Submit Button

      (SubmitCollector)

      Sends the collected data to PingOne to continue the DaVinci flow.

      1.0.0

      1.0.0

      1.0.0

      Flow Button

      (FlowCollector)

      Triggers an alternative flow without sending the data collected so far to PingOne.

      1.0.0

      1.0.0

      1.0.0

      Label

      (LabelCollector)

      Display a read-only text label.

      1.1.0

      1.1.0

      1.1.0

      Radio / Dropdown

      (SingleSelectCollector)

      Collects a single value from a choice of multiple options.

      1.1.0

      1.1.0

      1.1.0

      HTTP Connector SK-Component support

      SK-Component (Collector)

      Description

      DaVinci module

      Android

      iOS

      JavaScript

      skIDP

      (IdpCollector)

      Presents a button to allow users to authenticate using an external identity provider, such as Apple, Facebook, or Google.

      1.1.0

      1.1.0

      1.1.0

      View unsupported features

      Verify that your flow does not depend on any unsupported elements:

      SKPolling components

      SKPolling components cannot be processed by the SDK and should not be included.

      Images

      Images included in the flow cannot be passed to the SDK.

  • PingOne Form Connector

    • Show Form capability

      View supported fields
      Custom Fields support

      Field (Collector)

      Description

      DaVinci module

      Android

      iOS

      JavaScript

      Text Input

      (TextCollector)

      Collects a single text string.

      1.1.0

      1.1.0

      1.1.0

      Password

      (PasswordCollector)

      Collects a single text string that cannot be read from the screen.

      1.1.0

      1.1.0

      1.1.0

      Dropdown

      (SingleSelectCollector)

      Collects a value from a dropdown containing one or more text strings.

      1.1.0

      1.1.0

      1.1.0

      Combobox

      (MultiSelectCollector)

      Collects a value from a dropdown containing one or more text strings, the user can enter their own text string.

      1.1.0

      1.1.0

      1.1.0

      Radio Button List

      (SingleSelectCollector)

      Collects a value from one or radio buttons.

      1.1.0

      1.1.0

      1.1.0

      Checkbox List

      (MultiSelectCollector)

      Collects the value of one or more checkboxes.

      1.1.0

      1.1.0

      1.1.0

      Toolbox support

      Field (Collector)

      Description

      DaVinci module

      Android

      iOS

      JavaScript

      Flow Button

      (FlowCollector)

      Presents a customized button.

      1.1.0

      1.1.0

      1.1.0

      Flow Link

      (FlowCollector)

      Presents a customized link.

      1.1.0

      1.1.0

      1.1.0

      Translatable Rich Text

      (TextCollector)

      Presents rich text that you can translate into multiple languages.

      1.1.0

      1.1.0

      1.1.0

      Social Login

      (IdpCollector)

      Presents a button to allow users to authenticate using an external identity provider, such as Apple, Facebook, or Google.

      1.1.0

      1.1.0

      1.1.0

Prerequisites

Node and NPM

The SDK requires a minimum Node.js version of 18, and is tested on versions 18 and 20. To get a supported version of Node.js, refer to the Node.js download page.

You will also need npm to build the code and run the samples.

Server configuration

You must configure your PingOne instance for use with the DaVinci client.

Ask your PingOne administrator to complete the following tasks:

  • Configure a DaVinci flow

  • Create a DaVinci application

  • Configure PingOne for DaVinci flow invocation

To learn how to complete these steps, refer to Launching a flow with a Ping SDK in the PingOne DaVinci documentation.

Step 1. Download the samples


To start this tutorial, you need to download the SDK sample apps repo, which contains the projects you will use.

  1. In a web browser, navigate to the SDK Sample Apps repository.

  2. Download the source code using one of the following methods:

    Download a ZIP file
    1. Click Code, and then click Download ZIP.

    2. Extract the contents of the downloaded ZIP file to a suitable location.

    Use a Git-compatible tool to clone the repo locally
    1. Click Code, and then copy the HTTPS URL.

    2. Use the URL to clone the repository to a suitable location.

      For example, from the command-line you could run:

      git clone https://github.com/ForgeRock/sdk-sample-apps.git

The result of these steps is a local folder named sdk-sample-apps.

Step 2. Install the dependencies


In the following procedure, you install the required modules and dependencies, including the Ping SDK for JavaScript.

  1. In a terminal window, navigate to the sdk-sample-apps/javascript/embedded-login-davinci folder.

  2. To install the required packages, enter the following:

    npm install

    The npm tool downloads the required packages, and places them inside a node_modules folder.

Step 3. Configure connection properties


In this step, you configure the sample app to connect to the authentication tree/journey you created when setting up your server configuration.

  1. Copy the .env.example file in the sdk-sample-apps/javascript/embedded-login-davinci folder and save it with the name .env within this same directory.

  2. Open the .env file and edit the property values to match the settings you configured in previous steps:

    VITE_SCOPE=$SCOPE
    VITE_WEB_OAUTH_CLIENT=$WEB_OAUTH_CLIENT
    VITE_WELLKNOWN_URL=$WELLKNOWN_URL
    1. In the VITE_SCOPE property, enter the scopes you want to assign users who complete authentication using the client, separated by spaces.

      Example:

      VITE_SCOPE="openid profile email address"

    2. In VITE_WEB_OAUTH_CLIENT, property, enter the ID of the client you are connecting to in PingOne.

      Example:

      VITE_WEB_OAUTH_CLIENT="6c7eb89a-66e9-ab12-cd34-eeaf795650b2"

      Refer to Get configuration values from PingOne for instructions of where to find this value.

    3. In the VITE_WELLKNOWN_URL property, enter the OIDC Discovery Endpoint value from the client you are connecting to in PingOne.

      Example:

      discoveryEndpoint = "https://auth.pingone.ca/3072206d-c6ce-ch15-m0nd-f87e972c7cc3/as/.well-known/openid-configuration"

      Refer to Get configuration values from PingOne for instructions of where to find this value.

    The result resembles the following:

    VITE_SCOPE="openid profile email address"
    VITE_WEB_OAUTH_CLIENT="sdkPublicClient"
    VITE_WELLKNOWN_URL="https://auth.pingone.ca/3072206d-c6ce-ch15-m0nd-f87e972c7cc3/as/.well-known/openid-configuration"

Step 4. Test the app


In the following procedure, you run the sample app that you configured in the previous step. The sample connects to your server and walks through the authentication journey you created in an earlier step.

After successful authentication, the sample obtains an OAuth 2.0 access token and displays the related user information.

  1. In a terminal window, navigate to the sdk-sample-apps/javascript/embedded-login-davinci folder.

  2. Use npm to run the sample:

    npm run dev
  3. In a web browser:

    1. Ensure you are NOT currently logged into the PingOne instance.

      If you are logged into the PingOne instance in the browser, the sample will not work.

      Logout of the PingAM instance before you run the sample.

    2. Navigate to the following URL:

      http://localhost:5173

      A form appears with "Username" and "Password" fields:

      The login page of the JavaScript DaVinci client sample.
      Figure 19. The login page of the JavaScript DaVinci client sample.
  4. Optionally, to register a new identity in PingOne, tap the No Account? Register now! link.

    This link is an example of a FlowButton.

    The app displays the registration screen:

    The DaVinci sample app registration screen
    Figure 20. The DaVinci sample app registration screen.
    1. Enter the details of the new identity, and then click Save.

      The app creates the new identity in PingOne and returns to the sign on screen.

  5. Enter the username and password of a PingOne identity, and then click Sign On.

    The app sends the credentials to PingOne for validation, and on success displays the user’s session info:

    The DaVinci sample app displaying session info
    Figure 21. The DaVinci sample app displaying session info
  6. To get an access token for the user, click Get Tokens.

    The DaVinci sample app displaying tokens
    Figure 22. The DaVinci sample app displaying tokens
  7. To revoke the OAuth 2.0 token, click the Logout button.

    The application calls the /as/revoke endpoint to revoke the OAuth 2.0 token, and returns to the sign-in form.

Implement your use cases with the DaVinci client

The DaVinci client enables you to implement many authentication, registration, and self-service use cases into your mobile and web apps.

Visit the following pages for more information on implementing different use cases using the DaVinci client:

User Network

Applies to: Android | iOS | JavaScript

Add support for authenticating to your apps by using trusted Identity Providers (IdP), such as Apple, Facebook, and Google.

Set up social sign on with external IDPs

PingOne supports trusted Identity Providers (IdP), like Apple, Facebook, Google, and many others, providing authentication and identity verification on behalf of Ping Identity.

This is often referred to as social sign on or social authentication. These IdPs return the necessary user information for creating or validating accounts to your PingOne server.

The user is redirected from the client application to the IdP’s authorization server. Once on the IdP, the user authenticates, and provides the necessary consent required for sharing the information with PingOne. When the IdP authenticates your user, they are redirected back to your server to complete the flow. When PingOne completes the flow, it redirects the user to your app, where they are now signed on.

It’s common to offer these social login options in addition to traditional authentication with username and password, but they can be used alone.

Example Android app offering a combination of authentication methods.
Figure 23. An Android app with a combination of authentication methods

Steps

Complete the following steps to integrate social login into your client applications:

Before you begin

Before you begin this tutorial, ensure you have set up your PingOne instance with the required configuration.

For example, you will need an OAuth 2.0 client application setup.

Configure client apps for social sign on

Learn how to set up your Android, iOS, and JavaScript client apps to handle social sign on.

Before you begin

To complete this tutorial, refer to the prerequisites in this section.

The tutorial also requires a configured server.

Compatibility

PingOne
  • Your PingOne instance must have DaVinci enabled.

  • Only PingOne External IdPs are supported.

    • Identity providers configured using a DaVinci Service Connector are not yet supported.

Connecting external identity providers in PingOne

In this section, you configure PingOne with details about the social login identity providers you want to integrate into your client apps.

The Ping SDKs are compatible with any OpenID Connect 1.0-compliant Identity Provider, such as those available by default in PingOne.

You must configure the identity provider as a PingOne External IdP. Learn more in External IdPs .

Identity providers configured by using a DaVinci Service Connector are not yet supported.

Ping Identity has tested the steps in this tutorial with the Identity Providers listed below. Select a provider to view the PingOne documentation with instructions on how to configure an external IdP in PingOne:

Configuring DaVinci Flows for social sign on

After connecting your chosen external identity providers to PingOne, the next step is to configure a DaVinci flow to display buttons on your login pages so that users can choose to authenticate using the external IdP.

An Android app with three external IdP options; Google, Apple, and Facebook.
Figure 24. An Android app with three external IdP options: Google, Apple, and Facebook.

The Ping SDKs support two options for adding social sign on to your DaVinci flows:

Option A. Configuring DaVinci Forms for social sign on

Complete the following steps to integrate external IdPs with PingOne using DaVinci Forms.

Creating a DaVinci Form
  1. Create a form to display your selected external identity providers.

    PingOne includes a number of prebuilt templates that you can modify as required.

    Out-of-the-box DaVinci Forms templates.
  2. To add external identity providers to the form:

    1. From the Toolbox tab, drag a exit_to_app Social Login field onto the form for each external identity provider you want to display.

    2. In PingOne External Identity Provider, select the external IdP you created earlier. For example, Google.

      Configuring a Social Login field to use Google as the external IdP.
      Figure 25. Configuring a Social Login field to use Google as the external IdP.
  3. Save your changes.

Learn more in Creating a form in the PingOne documentation.

Adding a form to a DaVinci flow

When you have added your external identity providers to your form, you must now include it as part of your DaVinci flow.

  1. Add the form you created for external IdPs to a flow by using the PingOne Forms connector.

    Example of a Forms Connector in a DaVinci flow.
    Figure 26. Example of a Forms Connector in a DaVinci flow.
  2. To ensure the server can redirect back to an Android or iOS mobile app you must add a custom URI scheme.

    This is not required if you are only implementing a JavaScript client

    Select the PingOne Forms connector you just added, click the General tab, and in Application Return URL, enter a custom URI scheme for redirecting users to your client app after social sign on.

    If you are implementing Android or iOS clients for this tutorial, use myapp://example.com.

    Configuring a return URL in the PingOne Form Connector.
    Figure 27. Configuring a return URL in the PingOne Form Connector.
  3. Apply your changes.

Option B: Configuring the HTTP Connector for social sign on

Complete the following steps to integrate external IdPs with PingOne by adding the HTTP Connector to a DaVinci flow.

Adding the HTTP Connector to a DaVinci flow
  1. You must add the HTTP connector to your DaVinci flow so that it can display your custom HTML sign-on page.

    An HTTP connector added to a DaVinci flow.
    Figure 28. An HTTP connector added to a DaVinci flow.

    To learn more, refer to Adding a connector.

Building a custom HTML sign-on page

With the HTTP Collector in place in the flow, you can now add custom HTML to display the sign-on page.

  1. Select the HTTP Connector you added to your DaVinci flow, and add custom HTML to display a sign-on form.

    Example custom HTML form in an HTTP connector.
    Figure 29. Example custom HTML form in an HTTP connector.

    To learn more about adding custom HTML, refer to Building a custom page.

  2. Add an skIDP component to your custom HTML for each external IdP option you want to display.

    An HTTP connector with custom HTML showing 3 skIDP components.
    Figure 30. An HTTP connector with custom HTML showing three skIDP components.

    To learn more, refer to Adding SK-Components to a connector.

  3. Configure the skIDP component to use an external IdP:

    1. In the HTML Template field, select an skIDP component to view the Update Component modal.

    2. Select the Identity Provider tab.

    3. In Identity Provider Connector, select PingOne Authentication.

    4. In PingOne External Identity Provider, select one of the external IdPs you configured earlier.

    5. Enable Link with PingOne User.

      Failure to enable this option causes errors when attempting to use the flow with the Ping SDKs.

    6. To ensure the server can redirect back to an Android or iOS mobile app you must add a custom URI scheme.

      This is not required if you are only implementing a JavaScript client

      In Application Return to Url, enter a custom URI scheme for redirecting users to your client app after social sign on.

      If you are implementing Android or iOS clients for this tutorial, use myapp://example.com.

    The result will resemble the following:

    Configuring an skIDP component in an HTTP connector.
    Figure 31. Configuring an skIDP component in an HTTP connector.
  4. Save your changes.

Configuring a DaVinci flow to be launched by the Ping SDKs

Now that your DaVinci flow is configured to display your selected external IdPs you must configure PingOne so that you can launch the flow by using the Ping SDKs.

This involves performing the following high-level steps:

  1. Checking that your DaVinci flow uses only compatible connectors and fields.

  2. Creating an application in DaVinci to connect PingOne to the DaVinci flow.

  3. Creating an application in PingOne that the Ping SDKs can connect to and access the DaVinci application and its PingOne Flow Policy.

To learn how to complete the steps, refer to Launching a flow with a Ping SDK in the DaVinci documentation.

Next Steps

Now that you have configured PingOne with external IdPs, added them to a DaVinci flow, and configured applications so that the Ping SDKs, you are ready to connect the Ping SDKs.

Configure client apps for social sign on

Select your platform to discover how to configure your client application to perform social sign on with an external IdP.

Configure an Android app for social sign on

Perform the following steps to configure an Android app for social sign on.

Step 1. Add the dependencies

You must add the davinci and external-idp modules to your project:

  1. In the Project tree view of your Android Studio project, open the build.gradle.kts file.

  2. In the dependencies section, add the following:

    implementation("com.pingidentity.sdks:davinci:1.1.0")
    implementation("com.pingidentity.sdks:external-idp:1.1.0")

Step 2. Handle the redirect scheme

You must configure your Android app to open when the server redirects the user to the custom URI scheme you entered when setting up PingOne.

For this tutorial, the custom URI scheme is myapp://example.com.

To configure your app to open when using the custom URI scheme:

  1. In the Project tree view of your Android Studio project, open the build.gradle.kts file.

  2. In the android.defaultConfig section, add a manifest placeholder for the appRedirectUriScheme property that specifies the protocol of the custom schema:

    android {
        defaultConfig {
            manifestPlaceholders["appRedirectUriScheme"] = "myapp"
        }
    }

Step 3. Handling IdpCollector nodes

Your app must handle the IdpCollector node type that DaVinci sends when a user attempts to authenticate using an external IdP.

When encountering an IdpCollector node type, call idpCollector.authorize() to launch a custom tab and begin authentication with the external IdP:

var node = daVinci.start()

if (node is ContinueNode) {
    node.collectors.forEach {
        when (it) {
            is IdpCollector -> {
                when (val result = idpCollector.authorize()) {
                    is Success -> {
                        // When success, move to next Node
                        node.next()
                    }
                    is Failure -> {
                        // Handle the failure
                    }
                }
            }
        }
    }
}

Use the following parameters to the idpCollector.authorize() method to customize the appearance of the customTab it opens:

idpCollector.authorize {
    setShowTitle(false)
    setColorScheme(CustomTabsIntent.COLOR_SCHEME_DARK)
    setUrlBarHidingEnabled(true)
}

The idpCollector.authorize() method returns a Success result when authentication with the external IdP completes successfully. If not, it returns Failure and Throwable which shows the root cause of the issue.

val result = idpCollector.authorize()

result.onSuccess {
    // Move to next Node
}
result.onFailure {
    it // The Throwable
}

The result resembles the following:

An Android app with three external IdP options; Google, Apple, and Facebook.
Figure 32. An Android app with three external IdP options: Google, Apple, and Facebook.

Configure an iOS app for social sign on

Perform the following steps to configure an iOS app for social sign on.

Step 1. Add the dependencies

You must add the davinci and external-idp modules to your project. You can use either Cocoapods or Swift Package Manager (SPM) to add the dependencies.

You can use CocoaPods or the Swift Package Manager to add the PingOne Protect dependencies to your iOS project.

Add dependencies using CocoaPods
  1. If you do not already have CocoaPods, install the latest version.

  2. If you do not already have a Podfile, in a terminal window, run the following command to create a new Podfile:

    pod init
  3. Add the following lines to your Podfile:

    pod 'PingDavinci'
    pod 'External-idp'
  4. Run the following command to install pods:

    pod install
Add dependencies using Swift Package Manager
  1. With your project open in Xcode, select File > Add Package Dependencies.

  2. In the search bar, enter the Ping SDK for iOS repository URL: https://github.com/ForgeRock/ping-ios-sdk.

  3. Select the ping-ios-sdk package, and then click Add Package.

  4. In the Choose Package Products dialog, ensure that the PingDavinci and PingExternalIdp libraries are added to your target project.

  5. Click Add Package.

  6. In your project, import the library:

    import PingDavinci
    import PingExternalIdp

Step 2. Handle the redirect scheme

You must configure your iOS app to open when the server redirects the user to the custom URI scheme you entered when setting up PingOne.

For this tutorial, the custom URI scheme is myapp://example.com.

To configure your app to open when using the custom URI scheme:

  1. In Xcode, in the Project Navigator, double-click your application to open the Project pane.

  2. On the Info tab, in the URL Types panel, configure your custom URL scheme:

    Custom URL Scheme

Step 3. Handling IdpCollector nodes

Your app must handle the IdpCollector node type that DaVinci sends when a user attempts to authenticate using an external IdP.

When encountering an IdpCollector node type, call idpCollector.authorize() to launch an in-app browser and begin authentication with the external IdP:

public class SocialButtonViewModel: ObservableObject {
    @Published public var isComplete: Bool = false
    public let idpCollector: IdpCollector

    public init(idpCollector: IdpCollector) {
        self.idpCollector = idpCollector
    }

    public func startSocialAuthentication() async → Result<Bool, IdpExceptions> {
        return await idpCollector.authorize()
    }

    public func socialButtonText() → some View {
        let bgColor: Color
        switch idpCollector.idpType {
        case "APPLE":
            bgColor = Color.appleButtonBackground
        case "GOOGLE":
            bgColor = Color.googleButtonBackground
        case "FACEBOOK":
            bgColor = Color.facebookButtonBackground
        default:
            bgColor = Color.themeButtonBackground
        }
        let text = Text(idpCollector.label)
            .font(.headline)
            .foregroundColor(.white)
            .padding()
            .frame(width: 300, height: 50)
            .background(bgColor)
            .cornerRadius(15.0)

        return text
    }
}

The idpCollector.authorize() method returns a Success result when authentication with the external IdP completes successfully. If not, it returns Failure and IdpExceptions, which shows the root cause of the issue.

Task {
    let result = await socialButtonViewModel.startSocialAuthentication()
    switch result {
    case .success(_):
        onNext(true)
    case .failure(let error): //<- Exception
        onStart()
    }
}

The result resembles the following:

Example iOS app with social sign on options.

Configure a JavaScript app for social sign on

Perform the following steps to configure a JavaScript app for social sign on.

Step 1. Add the module

You must add the davinci module to your project:

import { davinci } from '@forgerock/davinci-client';

Step 2. Handle the redirect back from the IdP

You must configure your JavaScript app to continue a flow when the server redirects the user back from the IdP.

Use the davinciClient.resume method to continue an existing flow, rather than start a new one.

const davinciClient = await davinci({ config });
const continueToken = urlParams.get('continueToken');
let resumed: any;

if (continueToken) {
  // Continue an existing flow
  resumed = await davinciClient.resume({ continueToken });
} else {
  // Setup configuration for a new flow
  await Config.setAsync(config);
}

Step 3. Handling IdpCollector nodes

Your app must handle the IdpCollector node type that DaVinci sends. The node contains details of the button to render and the URL, for example.

Use the davinciClient.externalIdp() method to obtain the details from the collector:

const collectors = davinciClient.getCollectors();

collectors.forEach((collector) => {
  if (collector.type === 'IdpCollector') {
    socialLoginButtonComponent(formEl, collector, davinciClient.externalIdp(collector));
  }
}

In this example, a socialLoginButtonComponent handles rendering the button:

Example social-login-button.ts file to render social sign-on buttons
import type { IdpCollector } from "@forgerock/davinci-client/types";

export default function submitButtonComponent(
  formEl: HTMLFormElement,
  collector: IdpCollector,
  updater: () => void
) {
  const button = document.createElement("button");

  button.value = collector.output.label;
  button.innerHTML = collector.output.label;

  if (collector.output.label.toLowerCase().includes('google')) {
    button.style.background = 'white'
    button.style.borderColor = 'grey'
  } else if (collector.output.label.toLowerCase().includes('facebook')) {
    button.style.color = 'white'
    button.style.background = 'royalblue'
    button.style.borderColor = 'royalblue'
  } else if (collector.output.label.toLowerCase().includes('apple')) {
    button.style.color = 'white'
    button.style.background = 'black'
    button.style.borderColor = 'black'
  }

  button.onclick = () => updater();

  formEl?.appendChild(button);
}

The result resembles the following:

Example JavaScript app with social sign on options.

DaVinci client API reference