User profile self-service in Android apps
PingOne Advanced Identity Cloud PingAM Android
You can run additional authentication journeys with the Orchestration SDKs in the same way as the initial journey that authenticates the user.
The only difference is that the Orchestration SDK automatically attaches the existing session to subsequent outgoing calls.
Your app should iterate through the callbacks in the journey in the same way as it would for the initial authentication journey.
Step 1. Starting additional journeys
Use the start() method to start additional journeys after initial authentication:
var node = journey.start("sdkProfileManagement") {
forceAuth = true
noSession = true
}
When launching additional journeys, you can optionally add parameters to control how the journey runs:
- forceAuth
-
Set this parameter to
trueto force traversal of an authentication journey, even if the user already has a valid session. - noSession
-
Set this parameter to
trueto prevent the authentication journey from issuing a new session token upon successful completion.If you don’t set this parameter, the Orchestration SDK replaces the initial session token with the new one from the additional journey.
Replacing the session also resets its time-to-live values.
Step 2. Handling callbacks from a self-service journey
The self-service journey returns one or more callbacks to display and update the user’s profile.
Common callbacks you might encounter in a user profile self-service journey include the following:
| Callback | Nodes | Description |
|---|---|---|
Collects a boolean-style confirmation, such as yes/no or true/false. |
||
Provides a list of choices and collects the selected choice. |
||
Collects a boolean-style confirmation, such as yes/no or true/false with an optional "Cancel" choice. |
||
Provides profile attributes that require user consent and collects consent from the user. |
||
Collects knowledge-based authentication (KBA) answers to questions defined in the user profile, or user-defined question and answer pairs. |
||
Collects a numeric attribute, such as size or age. |
||
Collects string attributes, such as city names, telephone numbers, and postcodes. |
||
Displays the current terms and conditions and collects the user’s agreement to them. |
You can access these with node.callbacks. Your app should iterate through the received callbacks and display the appropriate user interface to the user to update the values.
// Start the user profile self-service flow
var node = journey.start("sdkProfileManagement") {
forceAuth = true
noSession = true
}
when (node) {
is ContinueNode -> {
node.callbacks.forEach {
when (it) {
is BooleanAttributeInputCallback -> BooleanAttributeInputCallback(it, onNodeUpdated)
is ChoiceCallback -> ChoiceCallback(it, onNodeUpdated)
is ConfirmationCallback -> {
showNext = false
ConfirmationCallback(it, onNext)
}
is ConsentMappingCallback -> ConsentMappingCallback(it, onNodeUpdated)
is KbaCreateCallback -> KbaCreateCallback(it, onNodeUpdated)
is NumberAttributeInputCallback -> NumberAttributeInputCallback(it, onNodeUpdated)
is StringAttributeInputCallback -> StringAttributeInputCallback(it, onNodeUpdated)
is TermsAndConditionsCallback -> {
TermsAndConditionsCallback(it, onNodeUpdated)
}
}
}
}
is FailureNode -> {/* ... */}
is ErrorNode -> {/* ... */}
is SuccessNode -> {/* ... */}
}
Attribute collector callbacks will usually have a prompt property to describe the field, and a value field containing the current or default value.
@Composable
fun StringAttributeInputCallback(callback: StringAttributeInputCallback, onNodeUpdated: () -> Unit) {
var input by remember(callback) {
mutableStateOf(callback.value)
}
Row(modifier = Modifier
.padding(4.dp)
.fillMaxWidth()) {
OutlinedTextField(
modifier = Modifier,
value = input,
onValueChange = { value ->
input = value
callback.value = input
onNodeUpdated()
},
isError = callback.failedPolicies.isNotEmpty(),
supportingText = if (callback.failedPolicies.isNotEmpty()) {
@Composable {
Text(
text = callback.error(),
style = MaterialTheme.typography.bodySmall
)
}
} else null,
label = { Text(callback.prompt) },
)
}
}