Since iOS 8 we can use the Touch ID sensors in compatible devices and authenticate sensitive data in our own apps. Here’s how to do it, short and simple.
Framework
First we’ll need to add the Local Authentication Framework to our app. To do that, navigate to your target and find the Linked Framework and Libraries section at the bottom. Click that little plus icon and search for “local”.
Code
Now that the framework is linked, we’ll need to import it into the class that does the verifying. I’ll use a simple view controller from the Single View application template here.
1 |
@import LocalAuthentication; |
Nice. Now I’ll hook up an action to which the authentication can be triggered. Here’s what it looks like when we’re done:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
- (IBAction)authenticateTouchID { // create a context and error object LAContext *context = [[LAContext alloc]init]; NSError *error = nil; NSString *reason = @"We want to authenticate your fingerprints"; // check if the device supports Touch ID if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) { NSLog(@"Device supports Touch ID"); // authenticate the user [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:reason reply:^(BOOL success, NSError * _Nullable error) { // it worked! if (success) { NSLog(@"Successfully authenticated the user via Touch ID. HUZZAH!"); } else { NSLog(@"Could not authenticate the user via Touch ID. \nReason: %@ \nError Code: %ld", error.localizedDescription, error.code); // if the user chooses the password option if (error.code == -3) { // handle password input here NSLog(@"Let's ask for your password instead"); } } }]; } else { // Touch ID is not available NSLog(@"Touch ID is not available."); } } |
It looks a little scary, so let’s sift through this one step at a time. At the beginning we’ll create a Local Authentication Context. It’s just a class with one particular method we can call. We’ll also create an error object and a string that will appear as the message when the Touch ID view is brought up. The error allows us to check why Touch ID was not available at the end of our message if we so desire.
1 2 3 4 |
// create a context and error object LAContext *context = [[LAContext alloc]init]; NSError *error = nil; NSString *reason = @"We want to authenticate your fingerprints"; |
Next up we’ll check if Touch ID is actually available. We’ll do that my calling evaluatePolicy: on our context. If this is successful, the Touch ID check can go ahead. If not, we can either ignore it or implement something like a password check instead (I’ve only implemented a log message here).
If the check is successful we can do the actual authentication, using the same method. The parameter for checking is an enumeration with the awesome name LAPolicyDeviceOwnerAuthenticationWithBiometrics (biometrics being the fingerprint part of the context – perhaps when Apple release devices with retina scanners, face detection or DNA verification we’ll have other values here).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// authenticate the user [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:reason reply:^(BOOL success, NSError * _Nullable error) { // it worked! if (success) { NSLog(@"Successfully authenticated the user via Touch ID. HUZZAH!"); } else { NSLog(@"Could not authenticate the user via Touch ID. \nReason: %@ \nError Code: %ld", error.localizedDescription, error.code); // if the user chooses the password option if (error.code == -3) { // handle password input here NSLog(@"Let's ask for your password instead"); } } }]; |
Note that there is one other value in this enumeration called LAPolicyDeviceOwnerAuthentication. Don’t use that: although it’s available, and it brings up the lock screen’s familiar passcode entry view, it’s throwing an exception when I tried to use it. I’ve not found anything in the Apple documentation on this value, although Xcode does suggest it as part of code completion. Anyway, moving on…
It’s a long method that takes a completion block (reply), inside which we handle the authentication. If the Touch ID is not successful, iOS automatically brings up an additional option that asks for a password.
To handle a user pressing that option, we’ll check for the error.code property: if it’s -3, it means that the user has selected the Fallback Mechanism. We’ll handle it here. Handle other error codes here too if you like and let the user know what’s going on and why.
And that’s it! Everything else is handled by iOS.
Testing
You can test this code on Touch ID devices (iPhone 5s, iPad Air 2, etc) as well as on the simulator. By default Touch ID will be disabled. Enable it by heading over to Hardware – Touch ID Enrolled.
To trigger a correct or failed finger touch use the appropriate option under
Hardware – Simulate Finger Touch
.
Demo Project and Documentation
Here’s a demo project on GitHub that shows this code in action:
Here’s Apple’s official documentation about Touch ID:
- https://developer.apple.com/library/prerelease/ios/documentation/LocalAuthentication/Reference/LocalAuthentication_Framework/index.html#//apple_ref/doc/uid/TP40014520
- https://developer.apple.com/library/prerelease/ios/documentation/LocalAuthentication/Reference/LAContext_Class/index.html#//apple_ref/occ/cl/LAContext