Ping SDKs

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 1. 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.