User and Device Management
The PingOne Recognize SDK caches the enrolled user locally on the device.
From SDK v6.2.1, the SDK can cache several enrolled users on the same device. Learn more in User profiles.
There are use cases where it’s possible to delete the user from Server API and delete the device from Server API. The PingOne Recognize SDK isn’t 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. If you use multiple user profiles, the call validates the user and device of the active user profile.
User profiles
By default, the PingOne Recognize SDK assumes one enrolled user per device. From SDK v6.2.1, the SDK can cache several user profiles on the same device and maintains the mapping between each user profile and the underlying user identifier.
The user profile serves as an identifier, like a username, that you use inside your app to switch from one user to another, similar to the viewing profiles available on the major streaming platforms.
Multiple user profiles let your app support the following use cases without having to de-enroll between users:
-
One individual enrolls more than once, creating a different PingOne Recognize ID for each enrollment, all bound to the same app on the same device.
-
Several individuals enroll once each, with every PingOne Recognize ID bound to the same app on the same device.
Selecting a user profile
To enroll and authenticate against a specific user profile, pass the optional userProfile parameter to BiomEnrollConfig and BiomAuthConfig:
Android
// enrollment
val enrollConfiguration = BiomEnrollConfig(userProfile = "alice")
// authentication
val authConfiguration = BiomAuthConfig(userProfile = "alice")
iOS
// enrollment
let enrollConfiguration = BiomEnrollConfig(userProfile: "alice")
// authentication
let authConfiguration = BiomAuthConfig(userProfile: "alice")
Flutter
// enrollment
final enrollConfiguration = BiomEnrollConfig(userProfile: "alice");
// authentication
final authConfiguration = BiomAuthConfig(userProfile: "alice");
React Native
import Keyless, { BiomEnrollConfig, BiomAuthConfig } from '@react-native-keyless/sdk';
// enrollment
const enrollConfiguration = new BiomEnrollConfig({ userProfile: 'alice' });
// authentication
const authConfiguration = new BiomAuthConfig({ userProfile: 'alice' });
If you omit the parameter, the SDK works as before in single-user mode and stores the enrollment under the reserved identifier RECOGNIZE_DEFAULT_USER_PROFILE.
Don’t use RECOGNIZE_DEFAULT_USER_PROFILE as an identifier for your own user profiles. The SDK reserves this string for the default single-user profile.
|
Listing the user profiles
To retrieve the list of all the user profiles enrolled on the device, use the getUserProfiles() API.
React Native
import Keyless from '@react-native-keyless/sdk';
const listUserProfiles = async () => {
const result = await Keyless.getUserProfiles();
result.fold({
onSuccess: (profiles) => {
console.log("User profiles:", profiles);
},
onFailure: (error) => {
console.error("Failed to get user profiles:", error);
},
});
};
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(). With multiple user profiles, the user identifier refers to the active user profile.
Device Identifier
The device is identified by its public signing key. To retrieve it, use Keyless.getDevicePublicSigningKey().
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.
If you use multiple user profiles, pass the optional userProfile parameter to reset a specific user profile. If you omit the parameter, reset() resets the default user profile.
Android
fun reset(
userProfile: String? = null,
onCompletion: (KeylessResult<Unit, KeylessSdkError>) -> Unit
)
React Native
import Keyless from '@react-native-keyless/sdk';
const resetSdk = async () => {
const result = await Keyless.reset({ userProfile: "alice" });
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);
},
});
};