Biometric Authentication

Biometric Authentication

Face ID and Touch ID provide convenient and secure authentication. Proper implementation ensures fallback mechanisms and handles various edge cases.

Advanced Biometric Implementation:

import LocalAuthentication

class BiometricAuthManager {
    private let context = LAContext()
    
    enum BiometricType {
        case none
        case touchID
        case faceID
    }
    
    var biometricType: BiometricType {
        var error: NSError?
        
        guard context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, 
                                      error: &error) else {
            return .none
        }
        
        switch context.biometryType {
        case .faceID:
            return .faceID
        case .touchID:
            return .touchID
        default:
            return .none
        }
    }
    
    func authenticateWithBiometrics(reason: String, 
                                  fallbackTitle: String? = nil,
                                  completion: @escaping (Bool, Error?) -> Void) {
        
        // Configure context
        context.localizedFallbackTitle = fallbackTitle
        context.localizedCancelTitle = "Cancel"
        
        // Set timeout for Touch ID
        if #available(iOS 10.0, *) {
            context.touchIDAuthenticationAllowableReuseDuration = 30.0
        }
        
        // Evaluate policy
        context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics,
                             localizedReason: reason) { success, error in
            DispatchQueue.main.async {
                if success {
                    completion(true, nil)
                } else {
                    // Handle specific error cases
                    if let laError = error as? LAError {
                        switch laError.code {
                        case .userFallback:
                            // User tapped fallback button
                            self.authenticateWithPasscode(completion: completion)
                        case .userCancel:
                            // User cancelled
                            completion(false, error)
                        case .biometryLockout:
                            // Too many failed attempts
                            self.authenticateWithPasscode(completion: completion)
                        default:
                            completion(false, error)
                        }
                    } else {
                        completion(false, error)
                    }
                }
            }
        }
    }
    
    private func authenticateWithPasscode(completion: @escaping (Bool, Error?) -> Void) {
        let context = LAContext()
        context.evaluatePolicy(.deviceOwnerAuthentication,
                             localizedReason: "Enter your passcode") { success, error in
            DispatchQueue.main.async {
                completion(success, error)
            }
        }
    }
}