PingOne Recognize

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>?
}

Flutter

class EnrollmentSuccess {
    final String keylessId;
    final String? customSecret;
    final String? signedJwt;
    final String? clientState;
}

React Native

class EnrollmentSuccess {
  public readonly keylessId: string;
  public readonly customSecret: string;
  public readonly enrollmentFrame: string | null;
  public readonly signedJwt: string | null;
  public readonly clientState: string | null;
  }

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.