Configure DaVinci client for Android properties
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:
-
In the Project tree view of your Android Studio project, open the
Gradle Scripts/build.gradle.kts
file for the DaVinci module. -
In the
dependencies
section, add the following:implementation("com.pingidentity.sdks:davinci:1.0.0")
Example of thedependencies
section after editing:dependencies { val composeBom = platform(libs.androidx.compose.bom) implementation(composeBom) // DaVinci client implementation("com.pingidentity.sdks:davinci:1.0.0") ... implementation(libs.androidx.core.ktx) implementation(libs.androidx.appcompat) implementation(libs.material) }
Configuring connection properties
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:
Property | Description | Required? | ||
---|---|---|---|---|
|
Your PingOne server’s Example:
|
Yes |
||
|
The For example, |
Yes |
||
|
A set of scopes to request when performing an OAuth 2.0 authorization flow. For example, |
Yes |
||
|
The
For example, |
Yes |
||
|
A timeout, in seconds, for each request that communicates with the server. Default is |
No |
||
|
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:
|
No |
Example
The following shows an example DaVinci client configuration, using the underlying Oidc
module:
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"
}
}
Stepping through DaVinci flows
To authenticate your users the DaVinci client for Android must start the flow, and step through each node.
Starting a DaVinci flow
To start a DaVinci flow, call the start()
method:
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 acollector
object, which describes the information it requires from the client.Learn more in Handling DaVinci flow collectors in continue nodes.
SuccessNode
-
This type indicates the flow is complete, and authentication was successful.
Learn more in Handling DaVinci flow success nodes.
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.
Learn more in Handling DaVinci flow error nodes.
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.
Learn more in Handling DaVinci flow failure nodes.
You can use the helper functions to determine which node type the server has returned:
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.
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.
next()
val next = node.next()
You do not need to pass any parameters into the |
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
.
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 |
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.
FailureNode
typeval 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:
SuccessNode
typeval 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:
// 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
}
}
}
when (val node = state.node) {
is ContinueNode -> {}
is ErrorNode -> {}
is FailureNode -> {}
is SuccessNode -> {}
}