How to accept Touch ID on macOS without triggering a Prompt

246 Views Asked by At

Is there a way to accept Touch ID, without triggering the default MacOS Touch ID prompt? Or is there a way to heavily customize the default Touch ID prompt?

I have seen 1Password do it, so it is possible.

I have tried following these tutorials, but they didn't work

Accessing Keychain Items with Face ID or Touch ID

Logging a User into Your App with Face ID or Touch ID

I have also read about Passkeys, but I don't think it will work because it's for Web Authentication.

Any pointers in the right direction will be greatly appreciated!

This is a screenshot of how 1Password does it:

enter image description here

1

There are 1 best solutions below

4
On

What you are trying to do isn't supported, at least not officially. You can try using custom UI overlay. The code is in swift.

import SwiftUI
import LocalAuthentication

struct ContentView: View {
    @State private var authenticationResult: AuthenticationResult?

    var body: some View {
        VStack {
            Text("Touch ID Authentication (add your custom text here)")
                .padding()

            Button("Authenticate with Touch ID") {
                authenticateWithTouchID()
            }
            .padding()

            if let result = authenticationResult {
                CustomResultView(result: result)
                    .padding()
            }
        }
    }

    func authenticateWithTouchID() {
        let context = LAContext()

        if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil) {
            context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: "Authenticate using Touch ID") { success, error in
                DispatchQueue.main.async {
                    if success {
                        authenticationResult = .success
                    } else {
                        authenticationResult = .failure
                    }
                }
            }
        } else {
            authenticationResult = .notAvailable
        }
    }
}

struct CustomResultView: View {
    let result: AuthenticationResult

    var body: some View {
        VStack {
            switch result {
            case .success:
                Image(systemName: "checkmark.circle")
                    .foregroundColor(.green)
                    .font(.system(size: 40))
                Text("Authentication Successful")
                    .foregroundColor(.green)

            case .failure:
                Image(systemName: "xmark.circle")
                    .foregroundColor(.red)
                    .font(.system(size: 40))
                Text("Authentication Failed")
                    .foregroundColor(.red)

            case .notAvailable:
                Image(systemName: "exclamationmark.circle")
                    .foregroundColor(.orange)
                    .font(.system(size: 40))
                Text("Touch ID not available or not configured")
                    .foregroundColor(.orange)
            }
        }
    }
}

enum AuthenticationResult {
    case success
    case failure
    case notAvailable
}

@main
struct TouchIDExampleApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}