Orchestration SDKs

Customizing device identifiers on Android

PingOne Advanced Identity Cloud PingAM Android

The Device Binding module uses the Device ID module to generate a unique identifier for the device. This ID is used to store and retrieve the details of the device from the user’s profile on the server.

The Device ID supports multiple strategies for generating an identifier, such as Android ID and keystore-based identifiers, ensuring flexibility and security for various use cases:

DefaultDeviceIdentifier

Uses the Android KeyStore for secure, persistent device identification.

This is the default option.

AndroidIDDeviceIdentifier

Uses the Android system-provided device identifier.

LegacyDeviceIdentifier

Provides compatibility with older device identification schemes.

The strategy you choose depends on your use case and requirements, as described in the following table:

Comparing Android device identifier strategies
Feature Default Device Identifier Android ID Device Identifier Legacy Device Identifier

Identifier Source

KeyStore-generated RSA key pair.

Settings.Secure.ANDROID_ID

KeyStore plus Android ID combination, or DefaultDeviceIdentifier.

Uniqueness

Unique to the app and device.

Unique per app signing key, user, and device. (API 26+)

Unique to the app and device. Compatible with legacy systems.

Persistence

Generates new ID when app reinstall.

Persists across app reinstall.

Depends on key existence, falls back to DefaultDeviceIdentifier.

Behavior on New Device

Different ID per device.

Different ID per device.

Different ID per device.

Behavior on Reinstall

Consistent if the KeyStore entries persist.

However, in general, the OS removes the KeyStore when uninstalling the app.

Consistent. (API 26+)

Consistent if the KeyStore entries persist.

However, in general, the OS removes the KeyStore when uninstalling the app.

Behavior on Data Clear

Change when clearing the KeyStore entries.

Consistent.

Change when clearing the KeyStore entries.

Security

Cryptographically secure, hardware-backed when available.

System-managed, read-only.

Combination of system ID and cryptographic material.

Select your preferred method for obtaining a device ID below to see how to implement it in your Android apps:

  • Default identifier

  • Android ID

  • Legacy identifier

  • Custom identifier

The DefaultDeviceIdentifier provides a secure, persistent identifier using the Android KeyStore:

// Get the KeyStore-based identifier
val deviceId = DefaultDeviceIdentifier.id

The DefaultDeviceIdentifier method perform the following steps to return a unique identifier:

  • Creates and stores a key pair in the Android KeyStore

  • Uses the public key as the basis for the device identifier

  • Hashes the key data using SHA-256 for added security

  • Caches the result for efficient access

Use AndroidIDDeviceIdentifier to retrieve the Android ID. The ANDROID_ID is a 64-bit unique identifier for each device:

// Get the Android ID-based identifier
val androidId = AndroidIDDeviceIdentifier.id

The ANDROID_ID returned by AndroidIDDeviceIdentifier:

  • Is unique to each combination of app-signing key, user, and device, on devices running Android 8.0 (API level 26) and higher.

  • Persists across app re-installs but may change on factory reset.

For applications transitioning from older SDKs, the LegacyDeviceIdentifier provides compatibility:

// Get the legacy identifier (compatible with older implementations)
val legacyId = LegacyDeviceIdentifier.id

The LegacyDeviceIdentifier method perform the following steps to return a unique identifier:

  • Attempts to retrieve a key from the KeyStore using the Android ID as the key alias

  • If found, creates a composite identifier compatible with legacy systems

  • If not found, falls back to the DefaultDeviceIdentifier

You can optionally define your own custom device identifier by implementing the DeviceIdentifier interface:

Example custom device identifier
class CustomDeviceIdentifier : DeviceIdentifier {
    override val id: String by lazy {
        // Generate a custom identifier based on your specific requirements
        val uniqueData = "your-unique-data-source"
        MessageDigest.getInstance("SHA-256")
            .digest(uniqueData.toByteArray())
            .joinToString("") { "%02x".format(it) }
    }
}

// Use your custom identifier
val customId = CustomDeviceIdentifier.id