Mobile SDK Enrollment
Enrollment is the process of registering a new user by connecting their facial biometrics to a PingOne Recognize account. During this process, a full and unobstructed view of the user’s face is required.
Android
val configuration = BiomEnrollConfig()
Keyless.enroll(
configuration = configuration,
onCompletion = { result ->
when (result) {
is Keyless.KeylessResult.Success -> Log.d("KeylessSDK ", "Enroll success - userId ${result.value.keylessId}")
is Keyless.KeylessResult.Failure -> Log.d("KeylessSDK ", "Enroll failure - error code ${result.error.code}")
}
}
)
iOS
let configuration = BiomEnrollConfig()
Keyless.enroll(
configuration: configuration,
onCompletion: { result in
switch result {
case .success(let enrollmentSuccess):
print("Enrollment finished successfully. UserID: \(enrollmentSuccess.keylessId)")
case .failure(let error):
print("Enrollment finished with error: \(error.message)")
}
})
Android 4.6
val configuration = EnrollmentConfiguration.builder.build()
Keyless.enroll(
enrollmentConfiguration = configuration,
onCompletion = { result ->
when (result) {
is Keyless.KeylessResult.Success -> Log.d("KeylessSDK ", "Enroll success - userId ${result.value.keylessId}")
is Keyless.KeylessResult.Failure -> Log.d("KeylessSDK ", "Enroll failure - error code ${result.error.code}")
}
}
)
iOS 4.6
let configuration = Keyless.EnrollmentConfiguration.builder.build()
Keyless.enroll(
enrollmentConfiguration: configuration,
onCompletion: { result in
switch result {
case .success(let enrollmentSuccess):
print("Enrollment finished successfully. UserID: \(enrollmentSuccess.keylessId)")
case .failure(let error):
print("Enrollment finished with error: \(error.message)")
}
})
Flutter
import 'package:keyless_flutter_sdk/keyless.dart';
import 'package:keyless_flutter_sdk/models/configurations/enrollment_configuration.dart';
final configuration = BiomEnrollConfig();
try {
final result = await Keyless.instance.enroll(configuration);
print("Enrollment finished successfully. UserID: ${result.keylessId}");
} catch (error) {
print("Enrollment finished with error: $error");
}
React Native
import Keyless, { BiomEnrollConfig } from '@react-native-keyless/sdk';
const enrollUser = async () => {
const enroll = new BiomEnrollConfig();
const result = await Keyless.enroll(enroll);
result.fold({
onSuccess: (data) => {
console.log(`Enrollment finished successfully. UserID: ${data.keylessId}`);
},
onFailure: (error) => {
console.error('Enrollment finished with error:', error);
},
});
};
enrollUser();
Enrollment Configuration
You can configure the enrollment process with optional parameters in your BiomEnrollConfig() instance or using the builder pattern methods from the EnrollmentConfiguration builder.
Android
public data class BiomEnrollConfig(
public val cameraDelaySeconds: Int = 2,
public val jwtSigningInfo: JwtSigningInfo?,
public val livenessConfiguration: LivenessSettings.LivenessConfiguration = LEVEL_1,
public val livenessEnvironmentAware: Boolean = true,
public val operationInfo: OperationInfo?,
public val shouldRetrieveEnrollmentFrame: Boolean = false,
public val showSuccessFeedback: Boolean = true,
public val showInstructionsScreen: Boolean = true,
public val showFailureFeedback: Boolean = true,
public val generatingClientState: ClientStateType? = null,
public val clientState: String? = null,
public val savingSecret: KeylessSecret? = null,
public val deletingSecret: KeylessSecret.Identifier? = null,
public val retrievingSecret: KeylessSecret.Identifier? = null,
public val shouldRetrieveSecretIDs: Boolean = false,
public val presentation: PresentationStyle = PresentationStyle.FULL_SCREEN
)
iOS
public struct BiomEnrollConfig {
public let cameraDelaySeconds: Int
public let customSecret: String?
public let jwtSigningInfo: JwtSigningInfo?
public let livenessConfiguration: Keyless.LivenessConfiguration
public let livenessEnvironmentAware: Bool
public let operationInfo: Keyless.OperationInfo?
public let shouldReturnEnrollmentFrame: Bool
public let showSuccessFeedback: Bool,
public let showInstructionsScreen: Bool,
public let showFailureFeedback: Bool,
public let generatingClientState: ClientStateType?,
public let clientState: String?,
public let deletingSecret: KeylessSecret.Identifier?
public let retrievingSecret: KeylessSecret.Identifier?
public let shouldRetrieveSecretIDs: Bool
public let presentationStyle: PresentationStyle
}
Android 4.6
public interface EnrollmentConfigurationBuilder {
public fun retrievingBackup(): EnrollmentConfigurationBuilder
public fun retrievingTemporaryState(): EnrollmentConfigurationBuilder
public fun savingSecret(customSecret: String): EnrollmentConfigurationBuilder
public fun withBackup(backupKey: ByteArray, backupData: ByteArray): EnrollmentConfigurationBuilder
public fun withDelay(cameraDelaySeconds: Int): EnrollmentConfigurationBuilder
public fun withEnrollmentSelfie(): EnrollmentConfigurationBuilder
public fun withLivenessSettings(
livenessConfiguration: LivenessSettings.LivenessConfiguration,
livenessTimeout: Int
): EnrollmentConfigurationBuilder
public fun withOperationInfo(
operationId: String,
payload: String? = null,
externalUserId: String? = null
): EnrollmentConfigurationBuilder
public fun withPin(pin: String): EnrollmentConfigurationBuilder
public fun withTemporaryState(temporaryState: String): EnrollmentConfigurationBuilder
public fun build(): EnrollmentConfiguration
}
iOS 4.6
public protocol EnrollmentConfigurationBuilder {
public func retrievingBackup() -> EnrollmentConfigurationBuilder
public func retrievingTemporaryState() -> EnrollmentConfigurationBuilder
public func savingSecret(_ customSecret: String) -> EnrollmentConfigurationBuilder
public func withBackup(_ backup: Keyless.Backup) -> EnrollmentConfigurationBuilder
public func withDelay(seconds: Int) -> EnrollmentConfigurationBuilder
public func withEnrollmentSelfie() -> EnrollmentConfigurationBuilder
public func withLivenessSettings(
livenessConfiguration: Keyless.LivenessConfiguration,
livenessTimeout: Int
) -> EnrollmentConfigurationBuilder
public func withOperationInfo(
id: String,
payload: String?,
externalUserId: String?
) -> EnrollmentConfigurationBuilder
public func withPin(_ pin: String) -> EnrollmentConfigurationBuilder
public func withTemporaryState(_ temporaryState: String) -> EnrollmentConfigurationBuilder
public func build() -> Keyless.EnrollmentConfiguration
}
Flutter
class BiomEnrollConfig {
final String? customSecret;
final String? temporaryState;
final OperationInfo? operationInfo;
final LivenessConfiguration? livenessConfiguration;
final int? livenessTimeout;
final bool? shouldRetrieveTemporaryState;
final int? cameraDelaySeconds;
final JwtSigningInfo? jwtSigningInfo;
final DynamicLinkingInfo? dynamicLinkingInfo;
final bool? showScreenInstructions;
final bool? showScreenSuccessFlow;
}
React Native
// The BiomEnrollConfig can be instantiated with these optional properties.
// example: new BiomEnrollConfig({ customSecret: 'your-secret', cameraDelaySeconds: 3 });
class BiomEnrollConfig {
public readonly livenessConfiguration: LivenessConfiguration;
public readonly livenessEnvironmentAware: boolean;
public readonly cameraDelaySeconds: number;
public readonly generatingClientState: ClientStateType | null;
public readonly shouldRetrieveEnrollmentFrame: boolean;
public readonly clientState: string | null;
public readonly customSecret: string | null;
public readonly iamToken: string | null;
public readonly operationInfo: OperationInfo | null;
public readonly jwtSigningInfo: JwtSigningInfo | null;
public readonly showSuccessFeedback: boolean;
public readonly showFailureFeedback: boolean;
public readonly showScreenInstructions: boolean;
}
Enrollment Success Result
Depending on the configuration options you enable, PingOne Recognize populates the corresponding fields in the EnrollmentSuccess result.
Android
data class EnrollmentSuccess(
val keylessId: String,
val enrollmentFrame: Bitmap?,
val signedJwt: String?,
val clientState: String?,
val secret: KeylessSecret?,
val secretIDs: Set<KeylessSecret.Identifier>?
) : KeylessSdkSuccess()
iOS
public struct EnrollmentSuccess {
public let keylessId: String?
public let enrollmentFrame: CGImage?
public let signedJwt: String?
public let clientState: String?
public let secret: KeylessSecret?
public let secretIDs: Set<KeylessSecret.Identifier>?
}
Configuration Options
Delaying the PingOne Recognize Evaluation/Decision
By default, the biometric decision-making process initiates immediately when the camera is invoked and the preview is showing. This maximises security, giving an attacker no additional preparation time while optimising the experience for genuine users.
The cameraDelaySeconds configuration is available to specify the delay (in seconds) between when the camera preview appears and when liveness processing starts.
|
Use careful consideration when implementing this feature for two reasons: (i) While this allows users to frame themselves and understand what is happening, it also gives attackers additional time to optimise their framing. (ii) Implementing a camera delay extends the "happy path" flow for all users. If the delay is too long, users may become frustrated and cancel the flow. |
Secret management
During enrollment, you can create, update, retrieve, and delete secrets, as well as list all stored secret IDs. Use savingSecret, retrievingSecret, deletingSecret, and shouldRetrieveSecretIDs configuration parameters. Retrieved secrets and secret IDs are available in the EnrollmentSuccess response. Learn more in Secret management.
JWT Signing Info
You can specify a payload to be added to a JWT signed by PingOne Recognize with the jwtSigningInfo parameter. See JWT signing for more details.
Liveness settings
Using livenessConfiguration you can configure the liveness security level during enrollment. The possible values are under LivenessSettings.LivenessConfiguration:
DEVELOPMENT
LEVEL_1 // recommended configuration
LEVEL_2
You can also set livenessEnvironmentAware (defaults to true) to help ensure the user is in a suitable setting for verification.
For more details, see the Liveness Settings section.
Operation info
The operationInfo parameter specifies a customizable unique operation identifier and associated payload stored on the PingOne Recognize backend if enrollment succeeds. Use this to add an extra level of confirmation to your operations.
Details on how to query stored operations are available in the Operations API.
Client state
PingOne Recognize users can be enrolled via IDV Bridge (Identity Verification Bridge). As a result of IDV Bridge enrollment, you receive a client state that registers users in your app without undergoing the full enrollment flow.
Use the clientState parameter to register users from a client state obtained through IDV-Bridge.
You can also use a client state to recover an account of an existing user who lost access. Follow the account recovery guide.
Enrollment frame
Integrators can specify whether to retrieve an enrollment frame captured during the user’s selfie capture during enrollment or account recovery. Set shouldReturnEnrollmentFrame to true on BiomEnrollmentConfig (defaults to false). If enrollment succeeds, retrieve the frame from the returned EnrollmentSuccess via enrollmentFrame.
Enrollment circuits
To speed up enrollment, use numberOfEnrollmentCircuits to upload fewer than the default of five circuits upon enrollment. The remainder (50 - numberOfEnrollmentCircuits) are uploaded asynchronously.
Presentation style
Use the presentationStyle parameter in BiomEnrollConfig to control how the enrollment UX/UI is presented during the enrollment flow.
-
Full Screen(default): Shows the standard full-screen enrollment experience. -
Overlay: Shows a streamlined and faster UX/UI, consistent with the authentication experience.
For UI customization options for this flow, see UI Customization.