2️⃣ Enrollment
Enrollment is the process of registering a new user by connecting their facial biometrics to a Keyless account. During this process, a full and unobstructed view of the user's face is required.
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}")
}
}
)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)
}
})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}")
}
}
)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)
}
})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");
}
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.
public data class BiomEnrollConfig(
public val cameraDelaySeconds: Int = 2,
public val customSecret: String?,
public val jwtSigningInfo: JwtSigningInfo?,
public val livenessConfiguration: LivenessSettings.LivenessConfiguration = PASSIVE_STANDALONE_HIGH,
public val livenessEnvironmentAware: Boolean = true,
public val operationInfo: OperationInfo?,
public val shouldRetrieveTemporaryState: Boolean = false,
public val shouldRetrieveEnrollmentFrame: Boolean = false,
public val temporaryState: String?,
public val showSuccessFeedback: Boolean = true,
public val showInstructionsScreen: Boolean = true,
public val showFailureFeedback: Boolean = true
)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 shouldRetrieveTemporaryState: Bool
public let shouldReturnEnrollmentFrame: Bool
public let temporaryState: String?,
public let showSuccessFeedback: Bool,
public let showInstructionsScreen: Bool,
public let showFailureFeedback: Bool
}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
}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
}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;
}
// The BiomEnrollConfig can be instantiated with these optional properties.
// example: new BiomEnrollConfig({ customSecret: 'your-secret', cameraDelaySeconds: 3 });
class BiomEnrollConfig {
public readonly operationInfo: OperationInfo | null;
public readonly jwtSigningInfo: JwtSigningInfo | null;
public readonly livenessConfiguration: LivenessConfiguration;
public readonly cameraDelaySeconds: number;
public readonly shouldRetrieveEnrollmentSelfie: boolean;
public readonly shouldRetrieveTemporaryState: boolean;
public readonly temporaryState: string | null;
public readonly customSecret: string | null;
public readonly iamToken: string | null;
public readonly showSuccessFeedback: boolean;
public readonly showFailureFeedback: boolean;
public readonly showInstructionsScreen: boolean;
}
Enrollment success result
Depending on the builder methods you enable, Keyless will populate the corresponding fields in the EnrollmentSuccess result reported below.
data class EnrollmentSuccess(Delaying the Keyless evaluation/decision
By default, our biometric decision making process initiates immediately on the camera being invoked and the camera preview showing. We believe this offers the maximum level of security in that an attacker is given no additional preparation time in front of the camera view, while at the same time we have looked to optimise the experience for genuine users i.e. delivering both approve and reject decisions in a way that feels natural and understandable to users.
However, we recognise that our customers, and their users, have different contexts and preferences and therefore the cameraDelaySeconds configuration is available to specify the delay (in seconds) between when the camera preview appears, and when the liveness processing starts. In effect, no decision, whether
Please note we advise careful consideration when implementing this feature for two reasons:
i) While this allows users to frame themselves and have longer to understand what is happening, is also time for any attackers to also optimise their framing.
ii) Implementing will ultimately mean that the "happy path" flow for all users is extended. If the delay is set for too long, some customers have noted that there is also the potential for some users to become frustrated and cancel/drop the flow.
We're happy to engage further in what the best trade-offs may be for customers, given our wide-ranging experience of assisting customers in live implementations.
val keylessId: String,
val customSecret: String = "",
val signedJwt: String? = null,
val enrollmentFrame: Bitmap? = null,
val temporaryState: String? = null
) : KeylessSdkSuccess()public struct EnrollmentSuccess {
public let keylessId: String?
public let customSecret: String?
public let enrollmentFrame: CGImage?
public let signedJwt: String?
public let temporaryState: String?
}class EnrollmentSuccess {
final String keylessId;
final String? customSecret;
final String? signedJwt;
final String? temporaryState;
}
class EnrollmentSuccess {
public readonly keylessId: string;
public readonly customSecret: string;
public readonly enrollmentSelfie: string | null;
public readonly userInfo: string | null;
public readonly signedJwt: string | null;
public readonly temporaryState: string | null;
}
Delaying the Keyless evaluation/decision
By default, our biometric decision making process initiates immediately on the camera being invoked and the camera preview showing. We believe this offers the maximum level of security in that an attacker is given no additional preparation time in front of the camera view, while at the same time we have looked to optimise the experience for genuine users i.e. delivering both approve and reject decisions in a way that feels natural and understandable to users.
However, we recognise that our customers, and their users, have different contexts and preferences and therefore the cameraDelaySeconds configuration is available to specify the delay (in seconds) between when the camera preview appears, and when the liveness processing starts. In effect, no decision, whether
Please note we advise careful consideration when implementing this feature for two reasons: i) While this allows users to frame themselves and have longer to understand what is happening, is also time for any attackers to also optimise their framing. ii) Implementing will ultimately mean that the "happy path" flow for all users is extended. If the delay is set for too long, some customers have noted that there is also the potential for some users to become frustrated and cancel/drop the flow. We're happy to engage further in what the best trade-offs may be for customers, given our wide-ranging experience of assisting customers in live implementations.
Custom secret
During enrollment you can specify a custom secret to be saved and encrypted along with the user's biometric data using savingSecret paramter. The custom secret can be anything you can save as an ASCII string, such as a secret that you have provided to the app from the backend, the seed of an OTP protocol, or anything else.
JWT Signing info
You can specify a payload to be added to a JWT signed by Keyless with the jwtSigningInfo parameter, more in JWT signing.
Liveness Settings
Using livenessConfiguration you can configure the liveness security level during enrollment. The possible liveness configuration are under LivenessSettings.LivenessConfiguration :
PASSIVE_STANDALONE_MEDIUM
PASSIVE_STANDALONE_HIGH //recommended configuration
PASSIVE_STANDALONE_HIGHESTYou can also specify a livenessEnvironmentAware that is by default se to true to enhance liveness detection. This parameters helps to ensure the user is in a suitable setting for verification.
More details on liveness in the dedicated liveness settings section.
Operation info
The parameter operationInfo specifies a customizable unique operation identifier and associated payload stored on the Keyless backend if the enrollment succeeds. Use this to add an extra level of confirmation in your operations.
Details on how to query our backend for stored operations are available on Operations API.
Temporary State
Keyless users can be enrolled via IDV-Bridge, Identity Verification Bridge. As a result of IDV-Bridge enrollment you receive a temporary state useful to register users in your app without undergoing the full enrollment flow.
Use the temporaryState parameter to register users from a temporary state obtained through IDV-Bridge.
You can also use a temporary state to recover an account of an existing user who lost access to the account. Follow the guide on account recovery.
Enrollment Frame
Integrators can specify whether or not to retrieve an enrollment frame, acquired during the user’s selfie capture during the enrollment or account recovery flow. You can achieve this by setting shouldReturnEnrollmentFrame to true on the BiomEnrollmentConfig (defaults to false). If the enrollment succeeds, you can retrieve the frame from the returned EnrollmentSuccess, via enrollmentFrame.
Enrollment circuits
To speed up enrollment you can use the numberOfEnrollmentCircuits to upload less than the default of five circuits upon enrollment. The remainder (50 - numberOfEnrollmentCircuits) are uploaded asynchronously.
Last updated
Was this helpful?