Orchestration SDKs

Completing backchannel authentication transactions on Android

PingOne Advanced Identity Cloud PingAM Android

A federation service that starts a backchannel authentication transaction on behalf of your user receives a backchannel transaction URI from PingOne Advanced Identity Cloud or PingAM, and is responsible for forwarding that URI to your app, for example over a push notification, a deep link, or another transport of your choosing.

The backchannel URI carries the details of the transaction as query parameters, for example:

https://openam-forgerock-sdks.forgeblocks.com/am/UI/Login?realm=%2Falpha&authIndexType=transaction&authIndexValue=1bb31b1d-6b5f-4d5f-9a2f-6a6a7f6a2b3e

Use the Journey module’s start(backchannelUri:configure:) method to complete the transaction on receipt of the URI.

The method extracts the transaction details from the backchannel transaction URI and drives the associated journey to completion, just like the standard start() method described in Starting an authentication journey on Android.

Step 1. Installing the Journey module

To install the Journey module into your Android 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 journey module as a dependency:

    dependencies {
        implementation("com.pingidentity.sdks:journey:2.1.0")
    }

Step 2. Configuring the Journey module

Import com.pingidentity.journey.Journey, then call Journey(), providing the Advanced Identity Cloud or PingAM server you want to target:

Configuring the Journey module
import com.pingidentity.journey.Journey

val journey = Journey {
    serverUrl = "https://openam-forgerock-sdks.forgeblocks.com/am"
    realm = "alpha"
    cookie = "ch15fefc5407912"
}

For the full range of configuration options available, see Configuring the Journey module on Android.

The Orchestration SDK uses the serverUrl and realm you provide when configuring Journey, rather than the host or realm parameter encoded in the backchannel transaction URI.

This means a malicious or malformed backchannel transaction URI cannot redirect the SDK to contact a different server.

Step 3. Completing a journey using a backchannel transaction URI

Pass the backchannel transaction URI to start() to start the journey the server configured for the transaction:

Starting a journey from a backchannel transaction URI on Android
// backchannelUri is the value your app received from the federation service.
var node = journey.start(backchannelUri = backchannelUri)

You can optionally apply parameters to start():

Adding parameters when starting a journey from a backchannel transaction URI
var node = journey.start(backchannelUri = backchannelUri) {
    forceAuth = true
    noSession = true
}

The parameters you might use in the start() method includes the following:

forceAuth

Set this parameter to true to force traversal of an authentication journey, even if the user already has a valid session.

Default is false.

noSession

Set this parameter to true to prevent the authentication journey from issuing a new session token upon successful completion.

Default is false.

Handle the returned node in exactly the same way as any other journey, as described in Navigating an authentication journey on Android. A transaction that has expired, was already completed, or wasn’t found returns an ErrorNode carrying the server’s message.

Starting a journey and handling the returned node on Android
// backchannelUri is the value your app received from the federation service.
val node = journey.start(backchannelUri = backchannelUri)

when (node) {
    is ContinueNode -> {
        // Provide input to any callbacks in the journey, such as a username and password
        node.callbacks.forEach { callback ->
            when (callback) {
                is NameCallback -> callback.name = "demo"
                is PasswordCallback -> callback.password = "5tr0ngP@S5w0rd!!"
                // Handle other callback types as they are introduced
            }
        }

        // Proceed to the next node with the provided input
        val nextNode = node.next()
    }
    is ErrorNode -> {
        // Handle server-side errors, such as an expired or already-completed transaction
        val errorMessage = node.message
    }
    is FailureNode -> {
        // Handle unexpected errors, such as network issues or a missing JourneyConfig
        val errorCause = node.cause
    }
    is SuccessNode -> {
        // Authentication successful, retrieve the session
        val session = node.session
    }
}