PingOne Recognize

User and Device Management

The PingOne Recognize SDK caches the enrolled user locally on the device.

There are use cases where it is possible to delete the user from Server API and delete the device from Server API . The PingOne Recognize SDK is not notified about such deletions. For this reason, if you try to authenticate a user or a device that has been deleted from Server API, you get an error.

Call validateUserAndDeviceActive before authenticating to validate that both the user and the device are still active in the PingOne Recognize backend. This avoids asking the user for biometric data when authentication would fail anyway.

Validate User and Device Active

Android

Keyless.validateUserAndDeviceActive(
    onCompletion = { result ->
        when (result) {
            is Keyless.KeylessResult.Success -> Log.d("KeylessSDK ", "user and device active")
            is Keyless.KeylessResult.Failure -> Log.d("KeylessSDK ", "user or device not found - error code ${result.error.code}")
            // error code 1131 = user is not enrolled on the device (not even locally, so did not check on backend)
            // error code 534 = user not found or deactivated on backend
            // error code 535 = device not found or deactivated on backend
        }
    }
)

iOS

Keyless.validateUserDeviceActive(
    completionHandler: { error in
        if let error = error {
            print("user or device deactivated")
            // error code 1131 = user is not enrolled on the device (not even locally, so did not check on backend)
            // error code 534 = user not found or deactivated on backend
            // error code 535 = device not found or deactivated on backend
        } else {
            print("user and device active")
        }
    }
)

Flutter

try {
  await Keyless.validateUserAndDeviceActive();
  print("user and device active");
} catch (error) {
  print("user or device deactivated - error code: ${error.code}");
  // error code 1131 = user is not enrolled on the device (not even locally, so did not check on backend)
  // error code 534 = user not found or deactivated on backend
  // error code 535 = device not found or deactivated on backend
}

React Native

import Keyless from '@react-native-keyless/sdk';

const validateUserAndDevice = async () => {
  const result = await Keyless.validateUserAndDeviceActive();

  result.fold({
    onSuccess: () => {
      console.log("user and device active");
    },
    onFailure: (error) => {
      console.error(`user or device deactivated - error code: ${error.code}`);
      // error code 1131 = user is not enrolled on the device (not even locally)
      // error code 534 = user not found or deactivated on backend
      // error code 535 = device not found or deactivated on backend
    }
  });
};

User Identifier

Retrieve the user identifier with Keyless.getUserId().

Android

fun getUserId(): KeylessResult<String, KeylessSdkError>

iOS

func getUserId() -> Result<String, KeylessSDKError>

Flutter

Future<String> getUserId() async

React Native

import Keyless from '@react-native-keyless/sdk';

const getUserId = async () => {
  const result = await Keyless.getUserId();

  result.fold({
    onSuccess: (userId) => {
      console.log("User ID:", userId);
    },
    onFailure: (error) => {
      console.error("Failed to get user ID:", error);
    },
  });
};

Device Identifier

The device is identified by its public signing key. To retrieve it, use Keyless.getDevicePublicSigningKey().

Android

fun getDevicePublicSigningKey(): KeylessResult<ByteArray, KeylessSdkError>

iOS

func getDevicePublicSigningKey() -> Result<String, KeylessSDKError>

Flutter

Future<String> getDevicePublicSigningKey() async

React Native

import Keyless from '@react-native-keyless/sdk';

const getDevicePublicSigningKey = async () => {
  const result = await Keyless.getDevicePublicSigningKey();

  result.fold({
    onSuccess: (key) => {
      console.log("Device public key:", key);
    },
    onFailure: (error) => {
      console.error("Failed to get device public key:", error);
    },
  });
};

PingOne Recognize SDK Reset

Resetting the PingOne Recognize SDK to a clean state deletes local data from the device, but does not de-enroll the user from the PingOne Recognize backend or deactivate the device from the PingOne Recognize backend.

Android

fun reset(
  onCompletion: (KeylessResult<Unit, KeylessSdkError>) -> Unit
)

iOS

func reset() -> KeylessSDKError?

Flutter

Future<void> reset() async

React Native

import Keyless from '@react-native-keyless/sdk';

const resetSdk = async () => {
  const result = await Keyless.reset();

  result.fold({
    onSuccess: () => {
      console.log("SDK reset successfully");
    },
    onFailure: (error) => {
      console.error("SDK reset failed:", error);
    },
  });
};

Lockout Management

The getRateLimitInfo API checks whether the user is currently rate-limited and, if so, for how many seconds. This API is typically used to provide feedback to users after multiple failed authentication attempts.

Android

Keyless.getRateLimitInfo { result ->
    when (result) {
        is Keyless.KeylessResult.Success -> {
            val rateLimitInfo = result.value
            println("User is rate limited: ${rateLimitInfo.isRateLimited} with remaining seconds: ${rateLimitInfo.remainingSeconds}")
        }
        is Keyless.KeylessResult.Failure -> {
            println("Error: ${result.error.message}")
        }
    }
}

iOS

Keyless.getRateLimitInfo(completion: { result in
    switch result {
    case .success(let success):
        print("User is rate limited: \(success.isRateLimited) with remaining seconds: \(success.remainingSeconds)")
    case .failure(let error):
        print("Error: \(error.message)")
    }
})

Flutter

try {
    final rateLimitInfo = await Keyless.instance.getRateLimitInfo();
    print("User is rate limited: ${rateLimitInfo.isRateLimited} with remaining seconds: ${rateLimitInfo.remainingSeconds}");
} catch (error) {
    print("Error: $error");
}

React Native

import Keyless from '@react-native-keyless/sdk';

const getRateLimitInfo = async () => {
  const result = await Keyless.getRateLimitInfo();

  result.fold({
    onSuccess: (info) => {
      console.log(`User is rate limited: ${info.isRateLimited}, remaining seconds: ${info.remainingSeconds}`);
    },
    onFailure: (error) => {
      console.error("Error fetching rate limit info:", error);
    },
  });
};