# Prerequisites

First, the user has to be an approved customer by having completed the onboarding flow. Check the image below for more information:

### Initialize Incode Welcome SDK as described [here](https://developer.incode.com/docs/user-guide\#1-initialize-welcome-sdk).

# 1:N Face Login - Identify a user

1:N Face login is suitable if you would like to identify a user by doing a face scan. This will execute a face match comparison across your entire user database and checks if the face corresponds to any of the approved users.

### To execute 1:N Face Login call `startFaceLogin` method:

Kotlin

```kotlin
IncodeWelcome.getInstance()
    .startFaceLogin(activityContext, SelfieScan.Builder().build(), object : SelfieScanListener {
        override fun onSelfieScanCompleted(selfieScanResult: SelfieScanResult) {
            if (selfieScanResult.status == SelfieScanResult.STATUS_OK) {
                val faceLoginResult = selfieScanResult.faceLoginResult
                if (faceLoginResult != null && faceLoginResult.success) {
                    val customerUUID = faceLoginResult.customerUUID
                    val token = faceLoginResult.token
                    val interviewId = faceLoginResult.interviewId
                    // ...
                } else {
                    val isSpoofAttempt = selfieScanResult.isSpoofAttempt ?: false
                    if (isSpoofAttempt) {
                        // Liveness failed
                    } else {
                        // User's face not found
                    }
                }
            } else {
                // Some of the preconditions for checking liveness failed, check selfieScanResult.status for specific info
            }
        }

override fun onError(error: Throwable) {
            // Some error occurred
        }

override fun onUserCancelled() {
            // User canceled login
        }
    })
```

Java

```java
IncodeWelcome.getInstance()
    .startFaceLogin(activityContext, new SelfieScan.Builder().build(), new SelfieScanListener() {
        @Override
        public void onSelfieScanCompleted(@NonNull SelfieScanResult selfieScanResult) {
            if (selfieScanResult.status == SelfieScanResult.STATUS_OK) {
                FaceLoginResult faceLoginResult = selfieScanResult.faceLoginResult;
                if (faceLoginResult != null && faceLoginResult.success) {
                    String customerUUID = faceLoginResult.customerUUID;
                    String token = faceLoginResult.token;
                    String interviewId = faceLoginResult.interviewId;
                    // ...
                } else {
                    boolean isSpoofAttempt = selfieScanResult.isSpoofAttempt != null ? selfieScanResult.isSpoofAttempt : false;
                    if (isSpoofAttempt) {
                        // Liveness failed
                    } else {
                        // User's face not found
                    }
                }
            } else {
                // Some of the preconditions for checking liveness failed, check selfieScanResult.status for specific info
            }
        }

@Override
        public void onError(@NonNull Throwable error) {
            // Some error occurred
        }

@Override
        public void onUserCancelled() {
            // User canceled login
        }
    });
```

# 1:1 Face Login - Verify the face of a specific user

1:1 Face Login is suitable if you want do a face authentication for a specific user that is already pre-authorized, meaning you already have the customer's UUID and only want to know if this exact person is trying to authenticate.

### To execute 1:1 Face Login call `startFaceLogin` method:

Kotlin

```kotlin
val selfieScanListener = object : SelfieScanListener {
    override fun onSelfieScanCompleted(selfieScanResult: SelfieScanResult) {
        when (selfieScanResult.status) {
            SelfieScanResult.STATUS_OK -> {
                val faceLoginResult = selfieScanResult.faceLoginResult;
                if (faceLoginResult != null && faceLoginResult.success) {
                    val customerUUID = faceLoginResult.customerUUID;
                    val token = faceLoginResult.token;
                    val interviewId = faceLoginResult.interviewId;
                    // ...
                } else {
                    val isSpoofAttempt = selfieScanResult.isSpoofAttempt ?: false;
                    if (isSpoofAttempt) {
                        // Liveness failed
                    } else {
                        // User's face is not similar to previously enrolled face
                    }
                }
            }
            else -> {
                // Some of the preconditions for checking liveness failed, check selfieScanResult.status for specific info
            }
        }
    }

override fun onError(error: Throwable) {
        // Some error occurred
    }

override fun onUserCancelled() {
        // User canceled login
    }
}

// ...

IncodeWelcome.getInstance()
    .startFaceLogin(
        activityContext,
        SelfieScan.Builder().setCustomerUUID("YOUR_CUSTOMER_ID").build(),
        selfieScanListener
    )
```

Java

```java
IncodeWelcome.getInstance()
    .startFaceLogin(activityContext, new SelfieScan.Builder().setCustomerUUID("YOUR_CUSTOMER_ID").build(), new SelfieScanListener() {
        @Override
        public void onSelfieScanCompleted(@NonNull SelfieScanResult selfieScanResult) {
            if (selfieScanResult.status == SelfieScanResult.STATUS_OK) {
                FaceLoginResult faceLoginResult = selfieScanResult.faceLoginResult;
                if (faceLoginResult != null && faceLoginResult.success) {
                    String customerUUID = faceLoginResult.customerUUID;
                    String token = faceLoginResult.token;
                    String interviewId = faceLoginResult.interviewId;
                    // ...
                } else {
                    boolean isSpoofAttempt = selfieScanResult.isSpoofAttempt != null ? selfieScanResult.isSpoofAttempt : false;
                    if (isSpoofAttempt) {
                        // Liveness failed
                    } else {
                        // User's face is not similar to previously enrolled face
                    }
                }
            } else {
                // Some of the preconditions for checking liveness failed, check selfieScanResult.status for specific info
            }
        }

@Override
        public void onError(@NonNull Throwable error) {
            // Some error occurred
        }

@Override
        public void onUserCancelled() {
            // User canceled login
        }
    });
```

# Face Login result

The resulting `SelfieScanResult` object will have the following:

- `faceLoginResult` \- `FaceLoginResult` object that contains:
  - `success` \- True if face login was successful, false otherwise
  - `customerUUID` \- Customer UUID of the matched user, `null` otherwise
  - `token` \- Customer token of the matched user, `null` otherwise
  - `interviewId` \- Session interviewId from which the user got approved
  - `interviewToken` \- Session interviewToken which was used during user approval
  - `transactionId` \- Transaction ID of the face login attempt
- `isSpoofAttempt` \- Specifies if there was a spoof attempt or not
- `croppedSelfieImgPath` \- Cropped selfie image location taken during the selfie scan step
- `fullFrameSelfieImgPath` \- Full frame selfie image location taken during the selfie scan step
- `selfieEncryptedBase64` \- Encrypted Base64-encoded selfie image
- `selfieBase64` \- Base64-encoded selfie image
- `isFaceMatched` \- True if face login was successful, false otherwise. Same information as faceLoginResult.success
- `hasFaceMask` \- True if a face mask is detected, false otherwise. Null if a check wasn't performed
- `error` \- Throwable that describes the error that happened during the face login
- `resultCode` \- Result code common to all IncodeWelcome results

# Login parametrization

By default, Face Login will complete a liveness check and face match on the server. You can perform on-device liveness check and face match for offline use-cases.

### To switch to on-device liveness and on-device face recognition include:

1. In your module-level `app/build.gradle`, add an additional Incode dependency:

Groovy

```groovy
dependencies {
    ...
    implementation 'com.incode.sdk:model-liveness-detection:3.2.1'
    implementation 'com.incode.sdk:model-face-recognition:3.5.1'
}
```

Kotlin

```kotlin
dependencies {
    ...
    implementation("com.incode.sdk:model-liveness-detection:3.2.1")
    implementation("com.incode.sdk:model-face-recognition:3.5.1")
}
```

2. Specify `FaceAuthMode.LOCAL` when creating `SelfieScan` module

Kotlin

```kotlin
val selfieScan = SelfieScan.Builder()
    .setFaceAuthMode(SelfieScan.FaceAuthMode.LOCAL)
    .build()
```

Java

```java
SelfieScan selfieScan = new SelfieScan.Builder()
    .setFaceAuthMode(SelfieScan.FaceAuthMode.LOCAL)
    .build();
```

Note: `SelfieScan.FaceAuthMode.LOCAL` can work only in 1:1 mode and if the user's face template is already saved locally in the device. Templates get saved during successful onboarding or by using the `allowFaceAuthModeFallback` parameter (please check explanation below).

Other parameters to consider:

- `setCustomerUUID`: ID that uniquely identifies the pre-authorized user who is performing a face login. When set, 1:1 login is performed. When this value is null, 1:N login is performed.
- `setShowTutorials`: Show tutorials how to capture selfie before the actual scan. `true` by default.
- `setWaitForTutorials`: Hide the continue button in the tutorial screen while tutorial animation is playing, in order to make sure the user has seen the video before continuing. `true` by default.
- `setAllowFaceAuthModeFallback` \- Specify `true` if you would want to do a `SelfieScan.FaceAuthMode.SERVER` face login in case `SelfieScan.FaceAuthMode.LOCAL` couldn't be performed due to missing the face template on the device. This is applied only to 1:1 Face login.
- `setLensesCheckEnabled`: Set to false if you would like to disable lenses detection during selfie scan. `true` by default.
- `setMaskCheckEnabled`: Specify `true` to enable face mask check detection during face capture. `false` by default. The face mask check is performed on the server, unless a local mask detection dependency is included in the module-level `app/build.gradle`.
- `setBrightnessThreshold`: Adjust the minimum requirements for a well-lit face during capture. Increasing the value will be more restrictive and require better lighting conditions, decreasing the value will loosen requirements and allow capturing while being in a darker environment. You can set the value to 0 to ignore this setting. The value is set at 50 by default.
- `setCameraFacing`: Sets the direction that the camera faces. It can be `CameraFacing.FRONT` or `CameraFacing.BACK`. `CameraFacing.FRONT` by default.
- `setLogAuthenticationEnabled`: Specify `false` if, for example, you want to make sure that no network calls are being performed in `SelfieScan.FaceAuthMode.LOCAL` mode. Note that the authentication attempts won't be visible in the dashboard. `true` by default.
- `setAssistedOnboardingEnabled`: Enables assisted onboarding (back-camera-only onboarding). This is equivalent to `setCameraFacing(CameraFacing.BACK)`.
