---
title: Binding keys to a device in Android
description: PingOne Advanced Identity Cloud PingAM Android
component: orchsdks
page_id: orchsdks:journey:use-cases/device-binding/android-device-binding
canonical_url: https://developer.pingidentity.com/orchsdks/journey/use-cases/device-binding/android-device-binding.html
revdate: Tue, 29 Oct 2025 14:22:33 +0100
keywords: ["Device", "Hardware", "Source Code", "Integration", "SDK", "Android"]
section_ids:
  before_you_begin: Before you begin
  securing_access_to_the_keys: Securing access to the keys
  android_device-profile_modules: Installing modules
  binding_keys_to_a_device: Binding keys to a device
  customizing_binding_parameters: Customizing binding parameters
  verifying_bound_keys_on_a_device: Verifying bound keys on a device
  customizing_signing_parameters: Customizing signing parameters
  adding_custom_claims_when_signing_using_bound_keys: Adding custom claims when signing using bound keys
  handling_errors: Handling errors
  new-biometrics: Handling biometric enrollment invalidations
  key-removal: Handling key removal by the device
---

# Binding keys to a device in Android

[icon: circle-check, set=far]PingOne Advanced Identity Cloud [icon: circle-check, set=far]PingAM [icon: android, set=fab]Android

The Device Binding module provides secure device registration and authentication capabilities for Android applications.

It enables applications to bind cryptographic keys to a device and restrict access to those keys, using biometrics, a PIN, and other authentication methods.

## Before you begin

You need to create an authentication journey in your server using the appropriate nodes to enable device binding.

The nodes you can use for device binding Journeys include the follows:

* [Device Binding node](https://docs.pingidentity.com/auth-node-ref/latest/device-binding.html)

  Allows users to register one or more devices to their account. A user can bind multiple devices, and each device can be bound to multiple users.

  The client receives a `DeviceBindingCallback` when reaching this node in a journey.

* [Device Signing Verifier node](https://docs.pingidentity.com/auth-node-ref/latest/device-signing-verifier.html)

  Verifies possession of a registered bound device.

  The node requires the client device to sign a challenge string using the private key that corresponds to the public key stored on the server during initial binding.

  The client receives a `DeviceSigningVerifierCallback` when reaching this node in a journey.

* [Device Binding Storage node](https://docs.pingidentity.com/auth-node-ref/latest/device-binding-storage.html)

  Optionally persists collected device binding data to a user's profile in the identity store.

  By default, the **Device Binding node** stores device data in the user's profile. You can choose instead to store the device data in transient state, perhaps to run a custom script to extract additional context.

  In this case, you can use a **Device Binding Storage node** to store the data in the user's profile.

  This node runs entirely server-side, and doesn't send a callback to the client.

## Securing access to the keys

The Device Binding module supports four distinct methods for accessing the private key, each offering different levels of security and user experience.

You specify which authentication type your client uses in the configuration of the **Device Binding node**. To change the authentication type to access the keys, you'll need to rebind the client device

Supported authentication types to access bound keys

* Biometric Only

* Biometric with Fallback

* Application PIN

* No Authentication

|                     |                                                                                                                                                                                                                                                                                                                                   |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Type name           | `BIOMETRIC_ONLY`                                                                                                                                                                                                                                                                                                                  |
| Description         | Requires strict biometric authentication with no fallback options                                                                                                                                                                                                                                                                 |
| Security level      | **High**                                                                                                                                                                                                                                                                                                                          |
| User experience     | Streamlined for devices with reliable biometric sensors                                                                                                                                                                                                                                                                           |
| Behavior            | - Only accepts biometric authentication, such as a fingerprint, face recognition, or an iris scan

- Fails immediately if biometric authentication is unavailable or unsuccessful

- No option to fall back to device PIN, pattern, or password

- Ideal for high-security applications where biometric verification is mandatory |
| Use cases           | Financial applications, enterprise security, medical applications                                                                                                                                                                                                                                                                 |
| Device requirements | Must have functional biometric sensors and enrolled biometric data                                                                                                                                                                                                                                                                |

|                     |                                                                                                                                                                                                                                                                                                                                              |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Type name           | `BIOMETRIC_ALLOW_FALLBACK`                                                                                                                                                                                                                                                                                                                   |
| Description         | Prefers biometric authentication but allows fallback to device credentials                                                                                                                                                                                                                                                                   |
| Security level      | **Medium** to **High**                                                                                                                                                                                                                                                                                                                       |
| User experience     | Flexible with multiple authentication options                                                                                                                                                                                                                                                                                                |
| Behavior            | * The primary method is a biometric authentication, such as a fingerprint, face recognition, or an iris scan

* If biometric authentication fails or is unavailable, users can use device credentials

  * Device credentials include a PIN, a pattern, or a password set at the system level

* Provides better accessibility and usability |
| Use cases           | Consumer applications, general-purpose authentication, accessibility-focused apps                                                                                                                                                                                                                                                            |
| Device requirements | - Biometric sensors preferred, but not required

- Must configure the device lock screen                                                                                                                                                                                                                                                     |

|                     |                                                                                                                                                                                                                                                                                                 |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Type name           | `APPLICATION_PIN`                                                                                                                                                                                                                                                                               |
| Description         | Requires a custom PIN that the application manages entirely                                                                                                                                                                                                                                     |
| Security level      | **Medium**                                                                                                                                                                                                                                                                                      |
| User experience     | Consistent across all devices regardless of hardware capabilities                                                                                                                                                                                                                               |
| Behavior            | * Uses an application-specific PIN separate from device credentials

  * The application collects the PIN through a custom UI

  * The application securely stores PIN data using encrypted storage mechanisms

  * Independent of device biometric capabilities or system-level authentication |
| Use cases           | - Devices without biometric capabilities

- Applications requiring custom authentication flows

- Scenarios where users prefer PIN over biometric authentication

  * Cross-platform consistency requirements                                                                                   |
| Device requirements | None - works on all devices                                                                                                                                                                                                                                                                     |

|                         |                                                                                                                                                                                                                     |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Type name               | `NONE`                                                                                                                                                                                                              |
| Description             | No user authentication required to access cryptographic keys                                                                                                                                                        |
| Security Level          | **Low**                                                                                                                                                                                                             |
| User Experience         | Seamless with no authentication prompts                                                                                                                                                                             |
| Behavior                | * Users can access keys immediately without any verification

* No authentication prompts or delays

* Cryptographic operations proceed without user interaction

* Relies solely on device possession for security |
| Use cases               | - Applications with alternative security measures                                                                                                                                                                   |
| Security Considerations | Anyone with device access can use the cryptographic keys                                                                                                                                                            |
| Device Requirements     | None                                                                                                                                                                                                                |

## Installing modules

Use the following module in your Android apps to bind keys to a device:

* `binding`

You can optionally also install the following modules:

* `binding-ui`

* `binding-migration`

* `bcpkix-jdk18on` ([BouncyCastle](https://www.bouncycastle.org/) open-source cryptographic library)

To install these modules 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 `binding` module as a dependency:

   ```gradle
   dependencies {
     implementation("com.pingidentity.sdk:binding:2.0.0")
   }
   ```

3. Optionally, you can include the **binding-ui** dependency, which includes default UI components for the following user interactions:

   * **Application PIN Collection**

     A Jetpack Compose dialog for secure PIN entry with:

     * Custom PIN input field with masked characters

     * Show/hide PIN visibility toggle

     * Cancel and confirm buttons

     * Error handling and validation feedback

   * **User Key Selection**

     A default UI for multi-user scenarios that displays:

     * List of available user keys with user information

     * Selection interface when multiple users have registered devices

     * User-friendly key identification (username, creation date, etc.)

   To use the default UI dependency, add it as follows:

   ```gradle
   dependencies {
     implementation("com.pingidentity.sdk:binding:2.0.0")
     implementation("com.pingidentity.sdk:binding-ui:2.0.0")
   }
   ```

4. Optionally, you can include the **binding-migration** dependency, which helps to migrate users with binding keys created by versions of the legacy ForgeRock SDK for Android.

   The **binding-migration** module runs the following steps in the background and requires no additional configuration or user intervention:

   * **Detects Legacy Keys**: Scans for existing ForgeRock SDK device binding keys and metadata

   * **Seamless Migration**: Automatically migrates keys to the new SDK format during application startup

   * **Preserves User Experience**: Users don't need to re-register their devices after SDK upgrade

   * **One-Time Process**: Migration occurs once and removes legacy data after successful migration

   * **Backward Compatibility**: Ensures smooth transition from Legacy SDK without data loss

   To use the binding migration dependency, add it as follows:

   ```gradle
   dependencies {
     implementation("com.pingidentity.sdk:binding:2.0.0")
     implementation("com.pingidentity.sdk:binding-ui:2.0.0")
     implementation("com.pingidentity.sdk:binding-migration:2.0.0")
   }
   ```

5. Optionally, if you intend to use the **Application PIN** authentication method to access the private keys, add the following [BouncyCastle](https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk18on) dependency:

   ```gradle
   dependencies {
     implementation("com.pingidentity.sdk:binding:2.0.0")
     implementation("com.pingidentity.sdk:binding-ui:2.0.0")
     implementation("com.pingidentity.sdk:binding-migration:2.0.0")
     implementation("org.bouncycastle:bcpkix-jdk18on:1.82"
   }
   ```

## Binding keys to a device

To bind keys to a device, the Binding Module performs the following tasks:

1. **Validation**: Checks device support for authentication type

2. **Cleanup**: Removes existing keys for the user

3. **Key generation**: Creates new cryptographic key pair

4. **Authentication**: Verifies user identity

5. **JWT Signing**: Creates signed proof-of-possession

6. **Storage**: Saves user key meta data

Use the `deviceBindingCallback.bind()` method to bind keys to the device as follows:

Binding keys to an Android device

```kotlin
import com.pingidentity.device.binding.journey.DeviceBindingCallback

// Simple device binding with default configuration
val result = deviceBindingCallback.bind()

result.onSuccess { jwt ->
  // Device successfully bound, JWT contains proof
  println("Device bound successfully: $jwt")
}.onFailure { error ->
  // Handle binding failure
  println("Binding failed: ${error.message}")
}
```

### Customizing binding parameters

You can configure a number of parameters for binding, such as the device identifier, algorithm used, and the validity time:

Configuring key binding parameters on an Android device

```kotlin
val result = deviceBindingCallback.bind {
  // Device identification
  deviceName = "Babs' Phone"
  deviceIdentifier = DefaultDeviceIdentifier.id // Use the default device identifier strategy

  // Cryptographic settings
  signingAlgorithm = "RS256"

  // Timing configuration
  issueTime = { Instant.now() }
  expirationTime = { timeout -> Instant.now().plusSeconds(timeout.toLong()) }

  // Storage configuration
  userKeyStorage {
    storage {
      fileName = "user_keys"
    }
  }

  // Authentication configuration
  biometricAuthenticatorConfig {
    promptInfo = {
      setTitle("Device Registration")
      setSubtitle("Secure your account")
      setDescription("Use your fingerprint to register this device")
    }
  }
}
```

Learn about customizing the device identifier in [Customizing device identifiers on Android](android-device-ids.html).

## Verifying bound keys on a device

To verify that a device possesses a bound key, the Binding Module performs the following tasks:

1. **Validation**: Validates custom claims

2. **Key Lookup**: Finds appropriate user key

3. **Authentication**: Verifies user identity

4. **Challenge signing**: Signs server challenge

5. **JWT creation**: Creates verification JWT

Use the `deviceSigningVerifierCallback.sign()` method to verify possession of bound keys as follows:

Verifying key possession by signing data on an Android device

```kotlin
import com.pingidentity.device.binding.journey.DeviceSigningVerifierCallback

// Simple device signing
val result = deviceSigningVerifierCallback.sign()

result.onSuccess { jwt ->
  // Challenge successfully signed
  println("Challenge signed: $jwt")
}.onFailure { error ->
  // Handle signing failure
  println("Signing failed: ${error.message}")
}
```

### Customizing signing parameters

You can configure a number of device signing parameters, such as the algorithm used, and the prompts to display:

Configuring signing parameters on an Android device

```kotlin
val result = deviceSigningVerifierCallback.sign {
  // Signing algorithm
  signingAlgorithm = "RS512"

  appPinConfig {
    pinRetry = 3
    pinCollector {
      "1234".toCharArray()
    }
    prompt = Prompt("App Pin", "Enter your app pin", "App pin is required")
  }

  // User key selection strategy
  userKeySelector { keys ->
    // Select most recently created key
    keys.maxByOrNull { it.createdAt } ?: keys.first()
  }

  // Authentication configuration
  biometricAuthenticatorConfig {
    promptInfo = {
      setTitle("Verify Transaction")
      setDescription("Confirm this transaction with your fingerprint")
    }
  }
}
```

### Adding custom claims when signing using bound keys

When signing a server-provided challenge to verify possession of a bound key, you can add custom data to the resulting JSON Web Token (JWT). The server can access and use this data for context, or for auditing purposes.

Add a `claims` attribute to the configuration, including the key-value pairs you want to add to the JWT:

Adding custom claims to the JWT on an Android device

```kotlin
deviceSigningVerifierCallback.sign {
  claims {
    // Transaction details
    put("amount", "100.00")
    put("recipient", "babs@example.com")
    put("currency", "USD")

    // Device context
    put("ip_address", getClientIP())
    put("user_agent", getUserAgent())

    // Security context
    put("risk_score", calculateRiskScore())
    put("session_id", getSessionId())
  }
}
```

## Handling errors

The Device Binding module can generate several error messages when you call `bind()` or `sign()`. Handle these errors to ensure the best possible user experience.

**Common error codes and how to remediate them**

| Error                                | Description                                                                                                                                                                | Remediation                                                                                                                               |
| ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `DeviceNotSupportedException`        | The device lacks required capabilities, or the user hasn't enrolled.                                                                                                       | Retry with alternative authentication requirements that don't require biometrics.                                                         |
| `DeviceNotRegisteredException`       | No keys are available for signing. Either the device hasn't been registered, or the user has removed the authentication methods that protected the private key.            | Redirect the user to bind a new key to the device.Learn more in [Handling key removal by the device](#key-removal).                       |
| `TimeoutCancellationException`       | Operation exceeded timeout.                                                                                                                                                | Allow retry with a longer timeout.                                                                                                        |
| `InvalidClaimException`              | Reserved claim names used in custom claims parameter.You can't add custom claims that match the standard required claims in a JWT, such as `sub`, `exp`, `iat`, and `iss`. | Remove or rename the claims listed in the error so they do not clash.                                                                     |
| `AbortException`                     | The user aborted the operation.For example the user clicked **Cancel** rather than provide their fingerprint.                                                              | Handle gracefully, and don't show error.The user chose not to continue the authentication flow.                                           |
| `BiometricAuthenticationException`   | Biometric authentication failed.                                                                                                                                           | Retry biometric authentication, or offer an alternative authentication method that doesn't require biometrics.                            |
| `InvalidCredentialException`         | The user provided invalid credentials.For example, the user entered an incorrect PIN number.                                                                               | Allow retry and prompt for the correct credentials.                                                                                       |
| `CancellationException`              | Coroutine operation cancelled.                                                                                                                                             | Re-throw the exception to preserve cancellation semantics.                                                                                |
| `KeyPermanentlyInvalidatedException` | User binds keys to their device with `BiometricOnly` authentication and later enrolls a new fingerprint.                                                                   | User must perform device binding again to generate new keys.Learn more in [Handling biometric enrollment invalidations](#new-biometrics). |

The following example shows how to handle some of these exceptions:

Handling exceptions when binding keys to a device

```kotlin
deviceBindingCallback.bind().fold(
  onSuccess = { jwt ->
    // Handle success
    processBindingSuccess(jwt)
  },
  onFailure = { error ->
    when (error) {
      is DeviceNotSupportedException -> {
        logger.w("Device not supported: ${error.message}")
        showFallbackAuthentication()
      }
      is TimeoutCancellationException -> {
        logger.w("Binding operation timed out")
        retryWithLongerTimeout()
      }
      else -> {
        logger.e("Binding failed", error)
        showGenericError(error.message)
      }
    }
  }
)
```

### Handling biometric enrollment invalidations

Setting the `setInvalidatedByBiometricEnrollment` parameter to `true` when binding a new key to a device invalidates the key if the user enrolls a new fingerprint or changes the registered biometrics on the device. The Device Binding module returns `KeyPermanentlyInvalidatedException` in this case.

If the authentication method for signing is set to `BIOMETRIC_ONLY` the invalidated keys won't be available, so the user will need to bind a new key:

Handling `KeyPermanentlyInvalidatedException` exceptions

```kotlin
// Configuration that makes keys sensitive to biometric changes
biometricAuthenticatorConfig {
    keyGenParameterSpec {
        // This setting makes keys invalid when new biometrics are enrolled
        setInvalidatedByBiometricEnrollment(true)
        //setUnlockedDeviceRequired(true)
        //setUserAuthenticationValidWhileOnBody(true)
        //setUserPresenceRequired(true)
        //setIsStrongBoxBacked(false)
        //setInvalidatedByBiometricEnrollment(false)
    }
}

// When user enrolls new fingerprint, subsequent signing will fail
deviceSigningCallback.sign().onFailure { error ->
  when (error) {
    is KeyPermanentlyInvalidatedException -> {
      // Keys are permanently invalidated due to biometric enrollment
      logger.w("Device keys invalidated by biometric enrollment")
      redirectToDeviceBinding() // User must re-bind device
    }
  }
}
```

|   |                                                                                                                                                                           |
| - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | Not all Android devices support the `keyGenParameterSpec` options for configuring how they create keys.You should test the devices you want to support if you enable them |

### Handling key removal by the device

If a user disables all of the available authentication methods on their device, such as removing their fingerprints and the device PIN, Android automatically removes any keys protected by those methods from the KeyStore.

The Device Binding module returns `DeviceNotRegisteredException` in this case, and the user will need to bind a new key to their device:

Handling `DeviceNotRegisteredException` exceptions

```kotlin
// When all device authentication is removed, keys are deleted by Android KeyStore
deviceSigningCallback.sign().onFailure { error ->
  when (error) {
    is DeviceNotRegisteredException -> {
      logger.w("No device keys found - maybe removed due to authentication method removal")
      showMessage("Please enroll in biometrics or add a device PIN, then register your device")
      redirectToDeviceBinding() // User must re-bind device
    }
  }
}
```
