# Face Authentication

The Face Authentication module captures a returning user's face with the device camera and matches it against the face already enrolled for that user. It then returns a pass or fail result. iOS exposes two entry points: an in-flow **Face Authentication** step and a standalone **Face Login** API.

For an overview of this module and how it works, see [Face Authentication](https://developer.incode.com/docs/face-authentication).

How you use this module depends on your integration pattern. When the app defines the steps in code, you add the module to an `IncdOnboardingFlowConfiguration` as shown below; when the flow is defined in Dashboard, you reference it and let the back end drive the steps. See [Integration Approaches](https://developer.incode.com/docs/ios-flow-configuration).

**Availability:** The `-l` build variant.

## Add Face Authentication

Add the module with `addFaceAuthentication(configuration:)` on `IncdOnboardingFlowConfiguration`. Face Authentication runs against an existing enrolled user, so your session must identify that user. Every setting on `FaceAuthenticationConfiguration` has a default, so pass a default-initialized configuration for the standard behavior, or build a custom one.

```swift
// Default configuration
flowConfig.addFaceAuthentication(configuration: FaceAuthenticationConfiguration())

// Custom configuration
flowConfig.addFaceAuthentication(configuration: faceAuthConfig)
```

Face Authentication ships both a v1 (legacy) and a v2 capture UI; the active one is selected by the SDK based on your Incode configuration.

### Example

The example below builds a `FaceAuthenticationConfiguration` with tutorials and occlusion checks, adds it to the flow, and listens for the result through the `IncdOnboardingDelegate`.

```swift
let faceAuthConfig = FaceAuthenticationConfiguration(
    showTutorials: true,
    lensesCheck: true,
    faceMaskCheck: true
)

let flowConfig = IncdOnboardingFlowConfiguration()
flowConfig.addFaceAuthentication(configuration: faceAuthConfig)

IncdOnboardingManager.shared.startOnboarding(
    sessionConfig: IncdOnboardingSessionConfiguration(token: "<SESSION_TOKEN>"),
    flowConfig: flowConfig,
    delegate: self
)
```

```swift
// IncdOnboardingDelegate
func onFaceAuthenticationCompleted(_ result: FaceAuthenticationResult) {
    // Face authentication completed
}

func onError(_ error: IncdFlowError) {
    // Onboarding flow was aborted due to an error
}
```

## Configuration Options

Configure the module by passing named parameters to the `FaceAuthenticationConfiguration` initializer. These are write-only: set at initialization, but not readable back from an existing instance. The table below lists the most commonly used ones. Any `Bool?` check left `nil` falls back to the corresponding manager-level `faceAuth*` default.

| Option                 | Type                     | Description                                                                                                                                               |
| ---------------------- | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `deepsight`            | `DeepsightConfiguration` | Enables liveness/Deepsight configuration. Defaults to `.default`. The effective behavior can be governed by your back-end Flow or Workflow configuration. |
| `showTutorials`        | `Bool?`                  | Shows a tutorial before the scan. When `nil`, uses the manager's `faceAuthShowTutorials`.                                                                 |
| `autoCaptureTimeout`   | `Double?`                | Sets the auto-capture timeout, in seconds.                                                                                                                |
| `captureAttempts`      | `Int?`                   | Sets the number of capture attempts. When `nil`, uses the manager's `faceAuthMaxRetries`.                                                                 |
| `lensesCheck`          | `Bool?`                  | Enables eyeglass detection during capture. When `nil`, uses the manager's `faceAuthLensesCheck`.                                                          |
| `faceMaskCheck`        | `Bool?`                  | Enables face-mask detection during capture. When `nil`, uses the manager's `faceAuthFaceMaskCheck`.                                                       |
| `closedEyesCheck`      | `Bool?`                  | Enables closed-eyes detection during capture. When `nil`, uses the manager's `faceAuthClosedEyesCheck`.                                                   |
| `headCoverCheck`       | `Bool?`                  | Enables head-covering detection during capture. When `nil`, uses the manager's `faceAuthHeadCoverCheck`.                                                  |
| `imageQualitySeverity` | `ImageQualitySeverity`   | Sets how strict the image-quality check is during capture. Defaults to `.defaultValue`.                                                                   |
| `occlusionCheck`       | `OcclusionCheck`         | Enables a face occlusion check. Defaults to `.disabled`.                                                                                                  |

## Result

Face Authentication delivers a `FaceAuthenticationResult` to the `onFaceAuthenticationCompleted(_:)` callback on `IncdOnboardingDelegate`.

```swift
func onFaceAuthenticationCompleted(_ result: FaceAuthenticationResult)
```

`FaceAuthenticationResult` fields:

- `success: Bool?`: `true` if face authentication succeeded; otherwise, `false`.
- `customerUUID: String?`: The customer UUID associated with the authenticated face; `nil` when unavailable.
- `image: UIImage?`: The captured selfie image; `nil` when unavailable.
- `selfieBase64: String?`: The Base64-encoded selfie image; `nil` when unavailable.
- `selfieEncryptedBase64: String?`: The Base64-encoded encrypted selfie image; `nil` when unavailable.
- `error: FaceAuthenticationError?`: The module-specific error when authentication did not complete successfully; otherwise, `nil`.
- `videoRecordingError: FaceAuthenticationError?`: Set when video recording failed during capture, independent of the authentication outcome; `nil` when unavailable. Distinct from `error`; currently only ever carries `insufficientStorageForVideoRecording`.

## Errors

Module errors surface through `result.error` as a `FaceAuthenticationError`. Pattern-match it to react to a specific case:

```swift
if case .spoofAttemptDetected = result.error {
    // A spoof attempt was detected
}
```

`FaceAuthenticationError` cases:

- `error`
- `inactiveSession`
- `nonexistentCustomer`
- `lensesDetected`
- `faceMaskDetected`
- `headCoverDetected`
- `closedEyesDetected`
- `faceTooDark`
- `spoofAttemptDetected`
- `userIsNotRecognized`
- `selfieImageLowQuality`
- `hintNotProvided`
- `faceNotFound`
- `faceCroppingFailed`
- `faceTooSmall`
- `faceTooBlurry`
- `badPhotoQuality`
- `processingError`
- `badRequest`
- `deniedCameraPermissions`
- `userCancelled`
- `selfieFaceOccluded`
- `insufficientStorageForVideoRecording`
- `unknown`

Flow-level failures also arrive through the delegate's `onError(_:)`.

## Standalone: Face Login (`-l` variant)

### Basic Usage

Outside a flow, authenticate a returning user with `startFaceLogin`. Pass a `customerUUID` for 1:1 verification, or omit it (`nil`) for 1:N identification. `faceAuthMode` selects server-side matching (`.server`) or on-device matching (`.local`, which requires the `-l` build).

```swift
IncdOnboardingManager.shared.startFaceLogin(
    customerUUID: nil,          // nil → 1:N; set → 1:1
    faceAuthMode: .server,      // .server or .local (.local needs -l)
    faceAuthModeFallback: true,
    lensesCheck: true,
    faceMaskCheck: true
) { result in
    // SelfieScanResult (see the Selfie module)
}
```

### Full Signature

The call above uses the most common parameters; every parameter has a default, so you only pass the ones you need. The complete signature is:

```swift
func startFaceLogin(
    showTutorials: Bool? = nil,
    customerUUID: String? = nil,
    faceAuthMode: FaceAuthMode? = nil,
    faceAuthModeFallback: Bool? = nil,
    lensesCheck: Bool? = nil,
    faceMaskCheck: Bool? = nil,
    forceThemeBackground: Bool = false,
    logAuthenticationEnabled: Bool? = nil,
    customLogo: UIImage? = nil,
    streamFramesToken: String? = nil,
    completion: @escaping (_ result: SelfieScanResult) -> Void
)
```

The additional optional parameters are: `showTutorials` (show a tutorial before the scan), `forceThemeBackground`, `logAuthenticationEnabled`, `customLogo`, and `streamFramesToken`.

### Manage the Local Face Database

When matching on device, manage the local face database directly.

```swift
IncdOnboardingManager.shared.addFace(FaceInfo(faceTemplate: "…", customerUUID: "…", templateId: "…"))
IncdOnboardingManager.shared.removeFace(customerUUID: "…")
IncdOnboardingManager.shared.setFaces([FaceInfo(faceTemplate: "…", customerUUID: "…", templateId: "…")])
let faces = IncdOnboardingManager.shared.getFaces()
IncdOnboardingManager.shared.syncFaceLoginAttempts(delegate: nil) { ok, error in /* ok: Bool?, error: IncdLoginError? */ }
```

### Supporting Types

- `FaceAuthMode`: `.server` (liveness + match on the server), `.local` (on device, `-l` only).
- `FaceInfo`: `faceTemplate`, `customerUUID`, `templateId`.

<br />
