0Pricing
Swift Academy · Lesson

Biometric Authentication

Authenticate users with Face ID and Touch ID.

Biometric Authentication is a free Swift Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Swift Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Biometrics With LocalAuthentication

Face ID and Touch ID let users prove who they are without typing a password. The LocalAuthentication framework exposes this through LAContext, which evaluates an authentication policy and tells you whether the user passed.

import LocalAuthentication
let context = LAContext()
// One LAContext object drives a single auth attempt

Checking Availability First

Always call canEvaluatePolicy before prompting. The device may lack biometric hardware, the user may not be enrolled, or biometrics may be locked out. This returns a Bool and an error explaining why if it fails.

import LocalAuthentication
func canUseBiometrics() -> Bool {
    let context = LAContext()
    var error: NSError?
    return context.canEvaluatePolicy(
        .deviceOwnerAuthenticationWithBiometrics,
        error: &error)
}

The Two Policies

.deviceOwnerAuthenticationWithBiometrics requires Face ID or Touch ID with no passcode fallback. .deviceOwnerAuthentication tries biometrics but falls back to the device passcode. Choose based on whether a passcode is acceptable.

import LocalAuthentication
// Biometrics only (no passcode fallback):
let strict = LAPolicy.deviceOwnerAuthenticationWithBiometrics
// Biometrics with passcode fallback:
let lenient = LAPolicy.deviceOwnerAuthentication
_ = (strict, lenient)

Evaluating the Policy

evaluatePolicy performs the authentication, showing the system biometric sheet. The localizedReason string explains to the user why you are asking. The async form returns a Bool or throws.

import LocalAuthentication
func authenticate() async -> Bool {
    let context = LAContext()
    do {
        return try await context.evaluatePolicy(
            .deviceOwnerAuthentication,
            localizedReason:
                String(localized: "Unlock your account"))
    } catch {
        return false
    }
}

Detecting Biometry Type

After canEvaluatePolicy, context.biometryType tells you whether the device uses .faceID, .touchID, .opticID, or .none. Use it to show the correct icon and wording in your own UI.

import LocalAuthentication
func biometryLabel() -> String {
    let context = LAContext()
    _ = context.canEvaluatePolicy(
        .deviceOwnerAuthenticationWithBiometrics, error: nil)
    switch context.biometryType {
    case .faceID:  return "Face ID"
    case .touchID: return "Touch ID"
    case .opticID: return "Optic ID"
    default:       return "Passcode"
    }
}

Handling Errors

Failures arrive as LAError codes: .userCancel, .userFallback (chose passcode), .biometryLockout after too many failures, and .biometryNotEnrolled. Branch on these to give helpful guidance instead of a generic failure.

import LocalAuthentication
func describe(_ error: Error) -> String {
    guard let la = error as? LAError else { return "failed" }
    switch la.code {
    case .userCancel:        return "cancelled"
    case .biometryLockout:   return "locked out"
    case .biometryNotEnrolled: return "not set up"
    default:                 return "failed"
    }
}

The Face ID Usage String

To use Face ID you must add NSFaceIDUsageDescription to Info.plist explaining why. Omitting it crashes the app the first time you evaluate a Face ID policy. Touch ID needs no such key.

// Info.plist:
// NSFaceIDUsageDescription =
//   "We use Face ID to unlock your saved passwords."
let required = "NSFaceIDUsageDescription is mandatory"
_ = required

Customizing the Sheet

You can tailor the prompt: localizedCancelTitle renames the cancel button, and localizedFallbackTitle sets (or hides, when empty) the fallback option. Setting an empty fallback title suppresses the passcode option.

import LocalAuthentication
func configured() -> LAContext {
    let context = LAContext()
    context.localizedCancelTitle =
        String(localized: "Not now")
    context.localizedFallbackTitle = "" // hide fallback
    return context
}

Reusing a Successful Authentication

By default each evaluatePolicy reprompts. Setting touchIDAuthenticationAllowableReuseDuration lets a recent successful unlock satisfy a later check without a new prompt — useful for grouped sensitive actions within a short window.

import LocalAuthentication
func reusableContext() -> LAContext {
    let context = LAContext()
    context.touchIDAuthenticationAllowableReuseDuration = 30
    return context
}

Biometrics vs Keychain Gating

LAContext verifies the user but does not itself protect data. For true security, pair it with Keychain SecAccessControl so the secret is cryptographically unreadable until authentication succeeds — not merely hidden behind a checked Bool.

import LocalAuthentication
// A bare evaluatePolicy == true is bypassable if your
// logic is tampered with. Prefer SecAccessControl so
// the data is encrypted until auth succeeds.
let pairing = "combine LAContext with Keychain ACL"
_ = pairing

A Complete Unlock Flow

Combine availability check, type-aware messaging, evaluation, and error handling into one robust routine your UI can call.

import LocalAuthentication
func unlock() async -> Bool {
    let context = LAContext()
    var err: NSError?
    guard context.canEvaluatePolicy(
        .deviceOwnerAuthentication, error: &err) else {
        return false
    }
    return (try? await context.evaluatePolicy(
        .deviceOwnerAuthentication,
        localizedReason:
            String(localized: "Access your vault"))) ?? false
}

Quick Check

Recall the difference between the two main policies.

Recap

You learned biometric authentication:

  • Use LAContext and call canEvaluatePolicy before evaluatePolicy.
  • .deviceOwnerAuthenticationWithBiometrics is biometrics-only; .deviceOwnerAuthentication adds passcode fallback.
  • Read biometryType for correct wording; handle LAError codes like .biometryLockout.
  • Add NSFaceIDUsageDescription, and pair with Keychain SecAccessControl for real protection.

Frequently asked questions

Is the “Biometric Authentication” lesson free?

Yes — the full text of “Biometric Authentication” is free to read here on the web, and the Swift Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Swift Academy course, upgrade to CoddyKit PRO.

What will I learn in “Biometric Authentication”?

Authenticate users with Face ID and Touch ID. You practise Swift Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Swift Academy?

No prior experience is required. Swift Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Biometric Authentication” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Swift Academy lesson?

Yes. Every Swift Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Storing Secrets in the Keychain
  2. Keychain Access Control
  3. Biometric Authentication
  4. Data Protection and Encryption
← Back to Swift Academy