# 3️⃣ Authentication

Authentication is the biometric equivalent of "signing-in". During authentication Keyless compares the user's facial biometrics with the ones computed during [enrollment](https://docs.keyless.io/consumer/mobile-sdk-guide/enrollment).

If the biometrics match, Keyless authenticates the user.

{% tabs %}
{% tab title="Android" %}

```kotlin
val configuration = BiomAuthConfig()

Keyless.authenticate(
    configuration = configuration,
    onCompletion = { result ->
        when (result) {
            is Keyless.KeylessResult.Success -> Log.d("KeylessSDK ", "Authentication success")
            is Keyless.KeylessResult.Failure -> Log.d("KeylessSDK ", "Authentication failure - error code ${result.error.code}")
        }
    }
)
```

{% endtab %}

{% tab title="iOS" %}

```swift
let configuration = BiomAuthConfig()

Keyless.authenticate(
    configuration: configuration,
    onCompletion: { result in
        switch result {
        case .success(let success):
            print("Authentication success")
        case .failure(let error):
            break
        }
    })
```

{% endtab %}

{% tab title="Android 4.6" %}

```kotlin
val configuration = AuthenticationConfiguration.builder.build()

Keyless.authenticate(
    authenticationConfiguration = configuration,
    onCompletion = { result ->
        when (result) {
            is Keyless.KeylessResult.Success -> Log.d("KeylessSDK ", "Authentication success")
            is Keyless.KeylessResult.Failure -> Log.d("KeylessSDK ", "Authentication failure - error code ${result.error.code}")
        }
    }
)
```

{% endtab %}

{% tab title="iOS 4.6" %}

```swift
let configuration = Keyless.AuthenticationConfiguration.builder.build()

Keyless.authenticate(
    authenticationConfiguration: configuration,
    onCompletion: { result in
        switch result {
        case .success(let success):
            print("Authentication success")
        case .failure(let error):
            break
        }
    })
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:keyless_flutter_sdk/keyless.dart';
import 'package:keyless_flutter_sdk/models/configurations/authentication_configuration.dart';

final configuration = BiomAuthConfig();

try {
  final result = await Keyless.instance.authenticate(configuration);
  print("Authentication success");
} catch (error) {
  print("Authentication failure");
}
```

{% endtab %}

{% tab title="React Native" %}

```javascript
import Keyless, { BiomAuthConfig } from '@react-native-keyless/sdk';

const authenticateUser = async () => {
  const configuration = new BiomAuthConfig();

  const result = await Keyless.authenticate(configuration);

  result.fold({
    onSuccess: (data) => {
      console.log('Authentication success', data);
    },
    onFailure: (error) => {
      console.error('Authentication failure:', error);
    },
  });
};
```

{% endtab %}
{% endtabs %}

## Authentication configuration

You can configure the authentication process with optional parameters in your `BiomAuthConfig()` instance or using the builder pattern methods from the `AuthenticationConfiguration` builder.

{% tabs %}
{% tab title="Android" %}

```kotlin
public data class BiomAuthConfig(
    public val cameraDelaySeconds: Int = 0,
    public val jwtSigningInfo: JwtSigningInfo?,
    public val livenessConfiguration: LivenessSettings.LivenessConfiguration = LEVEL_1,
    public val livenessEnvironmentAware: Boolean = true
    public val operationInfo: OperationInfo?,
    public val shouldRemovePin: Boolean = false,
    public val shouldRetrieveSecret: Boolean = false,
    public val shouldDeleteSecret: Boolean = false,
    public val showSuccessFeedback: Boolean = true,
    public val generatingClientState: ClientStateType? = null
)
```

{% endtab %}

{% tab title="iOS" %}

```swift
public struct BiomAuthConfig: AuthConfig {
    public let cameraDelaySeconds: Int
    public let jwtSigningInfo: JwtSigningInfo?
    public let livenessConfiguration: Keyless.LivenessConfiguration
    public let livenessEnvironmentAware: Bool
    public let operationInfo: Keyless.OperationInfo?
    public let shouldRemovePin: Bool
    public let shouldRetrieveSecret: Bool
    public let shouldDeleteSecret: Bool
    public let showSuccessFeedback: Bool
    public let generatingClientState: ClientStateType?
}
```

{% endtab %}

{% tab title="Android 4.6" %}

```kotlin
interface AuthenticationConfigurationBuilder {

    fun retrievingBackup(): AuthenticationConfigurationBuilder

    fun retrievingSecret(): AuthenticationConfigurationBuilder

    fun deletingSecret(): AuthenticationConfigurationBuilder

    fun retrievingTemporaryState(): AuthenticationConfigurationBuilder

    fun withDelay(cameraDelaySeconds: Int): AuthenticationConfigurationBuilder

     fun withLivenessSettings(
        livenessConfiguration: LivenessSettings.LivenessConfiguration,
        livenessTimeout: Int
    ): AuthenticationConfigurationBuilder

    fun withMessageToSign(message: String): AuthenticationConfigurationBuilder

    fun withOperationInfo(
        operationId: String,
        payload: String? = null,
        externalUserId: String? = null
    ): AuthenticationConfigurationBuilder

    fun withPin(pin: String): AuthenticationConfigurationBuilder

    fun withSuccessAnimation(enabled: Boolean = true): AuthenticationConfigurationBuilder

    fun build(): AuthenticationConfiguration
}
```

{% endtab %}

{% tab title="iOS 4.6" %}

```swift
public class Builder {

    public func retrievingBackup() -> Builder

    public func retrievingSecret() -> Builder

    public func deletingSecret() -> Builder

    public func retrievingTemporaryState() -> Builder

    public func revokingDevice(id: String) -> Builder

    public func withDelay(seconds: Int) -> Builder

    public func withLivenessSettings(
        livenessConfiguration: LivenessConfiguration,
        livenessTimeout: Int
    ) -> Builder

    public func withMessageToSign(_ message: String) -> Builder

    public func withOperationInfo(
        id: String,
        payload: String? = nil,
        externalUserId: String? = nil
    ) -> Builder

    public func withPin(_ pin: String) -> Builder

    public func withSuccessAnimation(_ enabled: Bool) -> Builder

    public func build() -> AuthenticationConfiguration
}
```

{% endtab %}

{% tab title="Flutter" %}

```dart
class BiomAuthConfig extends AuthConfig {
    final LivenessConfiguration? livenessConfiguration;
    final int? livenessTimeout;
    final int? cameraDelaySeconds;
    final bool? shouldRetrieveTemporaryState;
    final String? b64NewDeviceData;
    final String? b64OldDeviceData;
    final String? deviceToRevoke;
    final bool? shouldRetrieveSecret;
    final bool? shouldRemovePin;
    final JwtSigningInfo? jwtSigningInfo;
    final DynamicLinkingInfo? dynamicLinkingInfo;
    final OperationInfo? operationInfo;
    final bool? showScreenSuccessFlow;
}
```

{% endtab %}

{% tab title="React Native" %}

```javascript
class BiomAuthConfig {
  public readonly shouldRemovePin: boolean;
  public readonly cameraDelaySeconds: number;
  public readonly showSuccessFeedback: boolean;
  public readonly shouldRetrieveSecret: boolean;
  public readonly shouldDeleteSecret: boolean;
  public readonly jwtSigningInfo: JwtSigningInfo | null;
  public readonly dynamicLinkingInfo: DynamicLinkingInfo | null;
  public readonly livenessConfiguration: LivenessConfiguration;
  public readonly livenessEnvironmentAware: boolean;
  public readonly deviceToRevoke: string | null;
  public readonly operationInfo: OperationInfo | null;
  public readonly generatingClientState: ClientStateType | null;
  public readonly shouldRetrieveAuthenticationFrame: boolean | null;
  public readonly presentationStyle: PresentationStyle;
}

```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
The `successAnimationEnabled` and later `showScreenSuccessFlow` field has been renamed to `showSuccessFeedback`, triggering a breaking change. Moreover the success animation is now shown by default.
{% endhint %}

## Authentication success result

Depending on the builder methods you enable, Keyless will populate the corresponding fields in the `AuthenticationSuccess` result reported below.

{% tabs %}
{% tab title="Android" %}

```kotlin
data class AuthenticationSuccess(
      val clientState: String?,
      val secret: KeylessSecret?,
      val secretIDs: Set<KeylessSecret.Identifier>?,
      val signedJwt: String?
) : KeylessSdkSuccess()
```

{% endtab %}

{% tab title="iOS" %}

```swift
public struct AuthenticationSuccess {
    public let clientState: String?,
    public let secret: KeylessSecret?
    public let secretIDs: Set<KeylessSecret.Identifier>?
    public let signedJwt: String?
}
```

{% endtab %}

{% tab title="Flutter" %}

```dart
class AuthenticationSuccess {
    final String? customSecret;
    final String? signedJwt;
    final String? temporaryState;
}
```

{% endtab %}

{% tab title="React Native" %}

```javascript
class AuthenticationSuccess {
  customSecret: string | null;
  signedJwt: string | null;
  clientState: string | null;
}
```

{% endtab %}
{% endtabs %}

### Backup data

{% hint style="warning" %}
Backup data is no longer recommended to perform account recovery and the feature has been removed from Android and iOS SDKs. Use the client state instead. Follow the guide on [account recovery](https://docs.keyless.io/consumer/mobile-sdk-use-cases/guide-account-recovery).
{% endhint %}

Keyless can generate backup data that you can use to recover an account.

To *create* the backup data use the `shouldRetrieveBackup` configuration parameter. Once authentication succeeds, copy the `backup` data from the `AuthenticationSuccess` result, and store it securely.

To recover an account, use `backup` parameter during enrollment more in [backup](https://github.com/KeylessTech/docs.keyless.io/blob/master/spaces/sdk-docs/mobile-sdks/broken-reference/README.md).

### Delaying the Keyless evaluation/decision

By default, our biometric decision is set at a default two second delay between the camera preview appearing and the liveness evaluation beginning. We believe this offers an acceptable balance between usability and security 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 change the delay (in seconds) between when the camera preview appears, and when the liveness evaluation starts. In effect, no decision, whether \\

{% hint style="danger" %}
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.
{% endhint %}

### Secret management

During authentication 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 `AuthenticationSuccess` response. See [Secret Management](https://docs.keyless.io/consumer/mobile-sdk-guide/user-and-device-management-1) for full details.

### 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](https://docs.keyless.io/consumer/mobile-sdk-reference/jwt-signing).

### Liveness Settings

Using `livenessConfiguration` you can configure the liveness security level during enrollment. The possible liveness configuration are under `LivenessSettings.LivenessConfiguration` :

```
DEVELOPMENT
LEVEL_1        //recommended configuration
LEVEL_2
```

You 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](https://docs.keyless.io/consumer/mobile-sdk-reference/liveness-settings) section.

### Operation info

The parameter `operationInfo` specifies a customizable *unique* operation identifier and associated payload stored on the Keyless backend if the authentication succeeds.

Details on how to query our backend for stored operations are available on [Operations API](https://docs.keyless.io/consumer/server-api/operations).

### Client State

Use the `generatingClientState` parameter of the `BiomEnrollConfig` or `BiomAuthConfig` to creata a client state useful for the [account recovery](https://docs.keyless.io/consumer/mobile-sdk-use-cases/guide-account-recovery).

### Camera Preview Customization (BETA)

Use the `presentationStyle` parameter in `BiomAuthConfig` to control camera preview behavior during authentication.

* `.cameraPreview` (default): Shows the standard live camera preview for user guidance.
* `.noCameraPreview`: Hides the camera preview entirely, enabling a faster, minimal interface similar to native biometric flows on mobile devices.

{% tabs %}
{% tab title="Android 5.2" %}

```kotlin
val configuration = BiomAuthConfig(presentationStyle = PresentationStyle.NO_CAMERA_PREVIEW)
Keyless.authenticate(configuration = configuration, onCompletion = { result ->
    // Handle result
})
```

{% endtab %}

{% tab title="iOS 5.2" %}

```swift
let configuration = BiomAuthConfig(presentationStyle: .noCameraPreview)
Keyless.authenticate(configuration: configuration, onCompletion: { result in
    // Handle result
})
```

{% endtab %}

{% tab title="Flutter" %}

```dart
import 'package:keyless_flutter_sdk/keyless.dart';
import 'package:keyless_flutter_sdk/models/configurations/authentication_configuration.dart';

final configuration = BiomAuthConfig(presentationStyle: PresentationStyle.NO_CAMERA_PREVIEW);

try {
  final result = await Keyless.instance.authenticate(configuration);
  print("Authentication success");
} catch (error) {
  print("Authentication failure");
}
```

{% endtab %}

{% tab title="React Native" %}

```javascript
import Keyless, { BiomAuthConfig } from '@react-native-keyless/sdk';

const authenticateUserWithNoCameraPreview = async () => {
  const configuration = new BiomAuthConfig({
      presentationStyle: PresentationStyle.NO_CAMERA_PREVIEW,
    });

  const result = await Keyless.authenticate(configuration);

  result.fold({
    onSuccess: (data) => {
      console.log('Authentication success', data);
    },
    onFailure: (error) => {
      console.error('Authentication failure:', error);
    },
  });
};
```

{% endtab %}
{% endtabs %}

***

Go [here](https://docs.keyless.io/consumer/mobile-sdk-reference/ui-customization) to view the UI customization for this flow.
