Orchestration SDKs

Integrating FIDO auth journeys in Android

PingOne Advanced Identity Cloud PingAM Android

The FIDO module offers a streamlined API for handling FIDO interactions, including registering and authenticating with passkeys.

It abstracts away the complexities of the underlying FIDO protocols, allowing you to quickly add strong authentication to your applications.

For an example of the journeys you can build with this module, see the sample passkey journey.

Before you begin

Ensure you have prepared your server for FIDO authentication in Android apps before attempting the steps on this page.

Step 1. Installing modules

To add FIDO to your Android apps you need this module:

  • fido

To install the module into your Android app:

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

  2. In the dependencies section, add the fido module as a dependency:

    dependencies {
      implementation("com.pingidentity.sdks:journey:2.2.0")
      implementation("com.pingidentity.sdks:fido:2.2.0")
    }
  3. Optionally, if your application needs to support devices running Android API 33 (Android 13) and older, add the Credentials Play Services Auth dependency to ensure proper FIDO functionality:

    dependencies {
      implementation("com.pingidentity.sdks:journey:2.2.0")
      implementation("com.pingidentity.sdks:fido:2.2.0")
      implementation("androidx.credentials:credentials-play-services-auth:1.6.0")
    }

    Adding this dependency ensures maximum backwards compatibility:

    • Android Credential Manager requires additional support libraries for API 33 and below

    • It provides backward compatibility for FIDO authentication on older Android versions

  4. Optionally, if your application needs to support non-discoverable FIDO credentials or physical security keys, add the Play Services FIDO dependency:

    dependencies {
      implementation("com.pingidentity.sdks:journey:2.2.0")
      implementation("com.pingidentity.sdks:fido:2.2.0")
      implementation("androidx.credentials:credentials-play-services-auth:1.6.0")
      implementation("com.google.android.gms:play-services-fido:XX.X.X")
    }

    Adding this dependency ensures maximum compatibility with FIDO credentials:

    • Supports non-discoverable FIDO credentials

    • Compatible with legacy FIDO implementations that require Play Services

Remember to synchronize your Gradle project after adding dependencies.

Step 2. Registering FIDO authenticators

To register a FIDO authenticator, use the register() function. The function returns either Success or Failure.

The Orchestration SDK provides the FidoRegistrationCallback class for handling the FIDO registration requests.

Registering a FIDO authenticator in a Advanced Identity Cloud or PingAM journey
if (node is ContinueNode) {
  node.callbacks.forEach { callback ->
    if (callback is FidoRegistrationCallback) {
      when (val result = callback.register()) {
        is Success -> {
          // Registration successful, proceed to the next step in the journey
          node = node.next()
          // Process the next node
        }
        is Failure -> {
          // Registration failed, handle the error
          val error: Throwable = result.error
          // Log or display the error message
        }
      }
    }
  }
}

Step 3. Authenticating using a FIDO authenticator

To authenticate using a registered FIDO authenticator, use the authenticate() function. The function returns either Success or Failure.

The Orchestration SDK provides the FidoAuthenticationCallback class for handling the FIDO authentication requests:

Authenticating with a FIDO authenticator in a Advanced Identity Cloud or PingAM journey
if (node is ContinueNode) {
  node.callbacks.forEach { callback ->
    if (callback is FidoAuthenticationCallback) {
      when (val result = callback.authenticate()) {
        is Success -> {
          // Authentication successful, proceed to the next step in the journey
          node = node.next()
          // Process the next node
        }
        is Failure -> {
          // Authentication failed, handle the error
          val error: Throwable = result.error
          // Log or display the error message
        }
      }
    }
  }
}

Step 4. Enabling passkey autofill (WebAuthn conditional UI)

Optionally, enable passkey autofill. Passkey autofill, also known as WebAuthn conditional UI, lets users sign in with a saved passkey directly from the autofill suggestions shown when they focus the username field, skipping the extra step of pressing a dedicated "Use a passkey" button.

Conditional UI is server-driven: after you configure the journey to enable it, the Orchestration SDK builds a pending credential request and attaches it to your username field. The passkey suggestion appears when the user focuses the field, and no modal dialog is shown.

Passkey autofill requires Android 15 (API level 35) or later. The feature uses the Android Credential Manager API; requests are routed through Credential Manager even if useFido2ApiClient is set to true.

To add passkey autofill support to your app:

  1. Check that the device supports conditional mediation using the isConditionalMediationSupported property, and build the pending request with the pendingAuthenticate() method:

    Feature-detecting conditional mediation and creating a pending request
    if (isConditionalMediationSupported) {
      callback.pendingAuthenticate()
        .onSuccess { pending ->
          // Attach pending.request to the username field
        }
        .onFailure { error ->
          // Fall back to the modal authenticate() method
        }
    }

    On devices where conditional mediation is not supported, pendingAuthenticate() fails fast with a GetCredentialUnsupportedException.

  2. Attach the pending request to the username field so that passkey suggestions are offered when the user focuses it:

    Attaching a pending request to the username field
    usernameEditText.pendingGetCredentialRequest = pending.request

    The pending request attaches to Android View objects only. There is no Compose equivalent, so in Compose apps, wrap an EditText in an AndroidView composable and attach the request to it.

  3. Await the result. The returned assertion has the same shape as the result of the modal authenticate() method:

    Awaiting the conditional authentication result
    launch {
      pending.await()
        .onSuccess { assertion ->
          // Authentication successful, proceed to the next step in the journey
        }
        .onFailure { error ->
          // Handle cancellation
        }
    }

The server receives the assertion automatically; you don’t need to submit the result yourself.

If the user dismisses the passkey suggestions, await() stays suspended and delivers no error. Keep the modal authenticate() method available as a fallback, for example as a Use a passkey button, and treat a non-completing request as the signal to fall back.

Call pending.cancel() to release a suspended await() when your screen goes away.

Customizing credential requests

After you complete the steps above, you can optionally customize the credential request objects you receive during FIDO registration and authentication requests.

This allows you to configure specific options such as timeout values, preferred authenticator types, or immediate availability preferences.

Customizing registration credential requests

You can customize CreatePublicKeyCredentialRequest by providing a lambda to the register() method. Use this method to set preferences such as preferImmediatelyAvailableCredentials during authenticator registration:

Customizing registration credential requests
val result = callback.register {
  onCreatePublicKeyCredentialRequest { originalRequest ->
    // Customize and return a new request
    CreatePublicKeyCredentialRequest(
      requestJson = originalRequest.requestJson,
      preferImmediatelyAvailableCredentials = true
    )
  }
}

Customizing authentication credential requests

You can customize the authentication credential request for both the Credential Manager and Google Play Services FIDO2 API by providing a lambda to the authenticate() method.

The FIDO module automatically uses the appropriate customizer, based on which API you use.

Customizing authentication credential requests
val result = callback.authenticate {
  // Customizer for Android Credential Manager API
  onGetPublicKeyCredentialOption { originalOption ->
    GetPublicKeyCredentialOption(
      requestJson = originalOption.requestJson,
      preferImmediatelyAvailableCredentials = true
    )
  }

  // Customizer for Google Play Services FIDO2 API
  onPublicKeyCredentialRequestOptions { originalOptions ->
    originalOptions.toBuilder()
      .setTimeoutSeconds(30.0) // Example: change timeout
      .build()
  }
}

Selecting the FIDO2 API

Android provides two APIs for performing FIDO authentication, and the Orchestration SDK uses one of them for each authentication call:

The two APIs keep separate credential stores, so a passkey registered through one API is not visible to the other.

By default, the Orchestration SDK selects the API at runtime: it uses the FIDO2 API when Google Play Services is available on the device, and the Credential Manager API otherwise.

You can override the selection for each authentication call by setting useFido2ApiClient in the authenticate() method, as follows:

Selecting the FIDO2 API when using authentication journeys
val result = callback.authenticate {
  useFido2ApiClient = false // Route this call through Credential Manager
}

The following table compares the two APIs:

FIDO2 API Credential Manager

Selected when

useFido2ApiClient = true, or by default when Google Play Services is available

useFido2ApiClient = false, or by default when Google Play Services is unavailable

Credential store

Google Password Manager

The device’s default credential provider, for example Google Password Manager, Samsung Pass, or 1Password

Passkey autofill (conditional mediation)

Not supported

Supported

Non-discoverable, device-bound credentials

Supported

Not supported

Set useFido2ApiClient = false to route the call through Credential Manager when your app needs to support passkey autofill or to honor the device’s default credential provider, such as Samsung Pass.

Set useFido2ApiClient = true when your app uses non-discoverable, device-bound credentials, which only the FIDO2 API supports.