LocalAuthentication Framework
What is LocalAuthentication?
The LocalAuthentication framework provides a simple API for evaluating biometric policies (Face ID, Touch ID) and device passcode. It abstracts the hardware differences between devices.
Basic Biometric Authentication
import LocalAuthentication
class AuthManager {
func authenticate(reason: String) async throws -> Bool {
let context = LAContext()
var error: NSError?
guard context.canEvaluatePolicy(
.deviceOwnerAuthenticationWithBiometrics,
error: &error
) else {
throw AuthError.biometricsUnavailable
}
let success = try await context.evaluatePolicy(
.deviceOwnerAuthenticationWithBiometrics,
localizedReason: reason
)
return success
}
}
Checking Biometric Type
func biometricType() -> LABiometryType {
let context = LAContext()
var error: NSError?
_ = context.canEvaluatePolicy(
.deviceOwnerAuthenticationWithBiometrics,
error: &error
)
switch context.biometryType {
case .faceID: return .faceID
case .touchID: return .touchID
case .opticID: return .opticID
@unknown default: return .none
}
}
Error Handling
func handleLAError(_ error: NSError) -> String {
switch LAError.Code(rawValue: error.code) {
case .userCancel:
return "Authentication cancelled by user"
case .userFallback:
return "User chose fallback authentication"
case .biometryLockout:
return "Biometrics locked due to too many failures"
case .biometryNotEnrolled:
return "No biometrics enrolled"
case .biometryNotAvailable:
return "Biometrics not available on this device"
default:
return "Authentication failed"
}
}
Biometric Policies
Authentication Policies
LocalAuthentication provides two main policies:
- deviceOwnerAuthenticationWithBiometrics: Biometric only, no passcode fallback
- deviceOwnerAuthentication: Biometric or device passcode
// Biometric only (no passcode fallback)
let biometricOnly = context.evaluatePolicy(
.deviceOwnerAuthenticationWithBiometrics,
localizedReason: "Unlock vault"
)
// Biometric or passcode
let biometricOrPasscode = context.evaluatePolicy(
.deviceOwnerAuthentication,
localizedReason: "Confirm payment"
)
Requiring Passcode After Biometric Failure
After multiple biometric failures, iOS automatically falls back to passcode with deviceOwnerAuthentication:
func authenticateForSensitiveAction() async throws {
let context = LAContext()
context.touchIDAuthenticationAllowableReuseDuration = 10
do {
let success = try await context.evaluatePolicy(
.deviceOwnerAuthentication,
localizedReason: "Authorize transfer of $500"
)
if success {
// Proceed with sensitive action
}
} catch {
// Handle error, show passcode fallback UI
}
}
Evaluating Policy with Retry
func authenticateWithRetry(maxAttempts: Int = 3) async throws -> Bool {
var attempts = 0
while attempts < maxAttempts {
let context = LAContext()
do {
let success = try await context.evaluatePolicy(
.deviceOwnerAuthenticationWithBiometrics,
localizedReason: "Authenticate to continue"
)
if success { return true }
} catch {
attempts += 1
if attempts >= maxAttempts {
throw AuthError.maxAttemptsReached
}
}
}
return false
}
Fallback Handling
Custom Fallback Title
You can customize the fallback button text shown to users:
let context = LAContext()
context.localizedFallbackTitle = "Use Passcode"
context.localizedCancelTitle = "Cancel"
Fallback to Passcode Entry
When biometrics fail or the user taps fallback, handle passcode entry:
func authenticateWithFallback() async throws -> Bool {
let context = LAContext()
do {
return try await context.evaluatePolicy(
.deviceOwnerAuthentication,
localizedReason: "Authenticate to access your account"
)
} catch LAError.userFallback {
// Show custom passcode entry screen
return await showPasscodeEntry()
} catch LAError.biometryLockout {
// Biometrics locked, require passcode
return await showPasscodeEntry()
} catch {
throw error
}
}
Biometric Changes Detection
Handle biometric changes like enrolling a new face or fingerprint:
func checkBiometricChange() {
let context = LAContext()
var error: NSError?
guard context.canEvaluatePolicy(
.deviceOwnerAuthenticationWithBiometrics,
error: &error
) else { return }
// Evaluate with LAPolicyDeviceOwnerAuthenticationWithBiometrics
// If biometry changes, the evaluation fails and you should
// require re-authentication and potentially re-encrypt stored keys
let state = context.evaluatedPolicyDomainState
// Store this state and compare on next launch
// If it changed, biometrics were modified
}
Privacy Requirements
Before using Face ID, add the NSFaceIDUsageDescription key to Info.plist with a clear explanation of why your app needs Face ID:
<key>NSFaceIDUsageDescription</key>
<string>We use Face ID to authenticate you and protect your financial data.</string>
Touch ID does not require a usage description but it is good practice to inform users.
Best Practices
- Always provide a passcode fallback option
- Handle all LAError cases gracefully
- Use localizedReason to explain why authentication is needed
- Store biometric state to detect enrollment changes
- Never store biometric data yourself, use the system framework
Quiz
1. What is the difference between deviceOwnerAuthenticationWithBiometrics and deviceOwnerAuthentication?
2. What key must you add to Info.plist for Face ID?
3. What should you do when LAError.biometryLockout occurs?
4. Why check evaluatedPolicyDomainState?
Flashcards
Question
What are the two main LAContext evaluation policies?
Click to reveal answer
Answer
deviceOwnerAuthenticationWithBiometrics (biometrics only) and deviceOwnerAuthentication (biometrics or passcode).
Question
What is localizedReason used for?
Click to reveal answer
Answer
It provides the message displayed to the user explaining why biometric authentication is required, such as Authorize payment.
Question
When does LAError.biometryLockout occur?
Click to reveal answer
Answer
After too many failed biometric attempts. The user must enter their passcode before biometrics can be used again.
Revision Notes
Key Takeaways
- 1. LocalAuthentication provides a unified API for Face ID and Touch ID
- 2. Always provide a passcode fallback option
- 3. Handle biometryLockout by requiring passcode
- 4. Check evaluatedPolicyDomainState to detect enrollment changes
- 5. Add NSFaceIDUsageDescription to Info.plist for Face ID
Interview Tips
- • Explain the difference between the two LAContext policies
- • Describe how to handle biometric fallback gracefully
- • Discuss how to detect biometric enrollment changes
- • Walk through implementing biometric authentication for a banking app
Cheat Sheet
Biometrics Quick Reference
- LAContext for biometric evaluation
- canEvaluatePolicy: check availability
- evaluatePolicy: perform authentication
- .deviceOwnerAuthenticationWithBiometrics: no passcode fallback
- .deviceOwnerAuthentication: allows passcode fallback
- NSFaceIDUsageDescription required in Info.plist
- Handle all LAError cases