Use Touch ID In Your Swift App

WHAT IS TOUCH ID?

With iOS 7 and the iPhone 5S release, Apple introduced Touch ID, a new way for users to authenticate by using their fingerprints to unlock their phones or purchases on the App Store. Now, in iOS 8, Apple provides an SDK for developers to use Touch ID in their apps, and, as you will see in this blog post, it’s actually very simple to add this feature to your app. Remember that Touch ID is only available for iPhone 5S and newer, iPad Air 2 and iPad Mini 3. That’s something to consider when you implement it in your app.

In this blog post, I will walk you through all the steps to implement Touch ID in your app — and of course, because we are curious developers, everything in this post will be coded in Swift. If you are not familiar with Swift yet, it’s probably a good time to read the iBook provided by Apple before reading this article.

 

DESCRIPTION OF THE FRAMEWORK

 

Apple implemented a framework called Local Authentication that you can use with a security policy to authenticate a user. This framework is based on one method:

func evaluatePolicy(policy: LAPolicy, localizedReason localizedReason: String!, 
reply: ((Bool, NSError!) -> Void)!)

This method will check the user identity for you. You can find more details in the Apple documentation or in the WWDC 2014 session Keychain and Authentication with Touch ID if you want to understand how it works exactly. The goal of this blog post is to focus on the framework implementation and the best practices when using Touch ID.

In this framework, one of the most important things is the different errors that you have to handle. Like I have mentioned, Touch ID is not available on all devices. Also, the technology is still new, so it may not recognize every user fingerprint correctly. The system can also cancel the fingerprint recognition in some situations (when you receive a phone call, for example). With all these possibilities, error management is crucial when working with Touch ID.

Below you can find the list of all the different errors. In your code, you will have to handle all of them (with custom error messaging, if possible) to enhance the user experience.

enum LAError : Int {
    case AuthenticationFailed
    case UserCancel
    case UserFallback
    case SystemCancel
    case PasscodeNotSet
    case TouchIDNotAvailable
    case TouchIDNotEnrolled
}

CONSTANTS:

  • AuthenticationFailed
    Authentication was not successful because the user failed to provide valid credentials.
  • UserCancel
    Authentication was canceled by the user—for example, the user tapped Cancel in the dialog.
  • UserFallback
    Authentication was canceled because the user tapped the fallback button (Enter Password).
  • SystemCancel
    Authentication was canceled by system—for example, if another application came to foreground while the authentication dialog was up.
  • PasscodeNotSet
    Authentication could not start because the passcode is not set on the device.
  • TouchIDNotAvailable
    Authentication could not start because Touch ID is not available on the device.
  • TouchIDNotEnrolled
    Authentication could not start because Touch ID has no enrolled fingers.

 

DEMO APP

 

Ready to build an app using Touch ID? Let’s start!

STEP 0: SET UP THE PROJECT AND THE STORYBOARDS, IMPORT THE FRAMEWORK, CREATE NECESSARY CLASSES

The first thing is to create a Swift project. Create a single view applicationand select Swift as the main project language.

Next, link LocalAuthentication.framework with your target.

Then, import the framework at the top of your view controller:

import LocalAuthentication

 

STEP 1: CREATE AUTHENTICATE METHOD

In the ViewController file, create a method to authenticate the user. This method will be responsible for initiating and handling Touch ID authentication.

func authenticateUser() {}

 

STEP 2: GET THE CURRENT CONTEXT

In this method, you need to get the device current authentication context:

func authenticateUser() {
    let context : LAContext = LAContext()
}

You’ll need this context object to ask for TouchID authentication.

Note: You don’t have to specify the type LAContext in Swift, but I prefer to do it to make the code easier to read.

STEP 3: DECLARE THE ERROR AND REASON STRING VARIABLES

You need an NSError to handle error management, and an NSString because Apple recommends that you display a quick explanation of why you are trying to authenticate the user using Touch ID. Put these inside authenticateUser:

var error : NSError?
var myLocalizedReasonString : NSString = "Authentication is required"

 

STEP 4: CHECK IF THE DEVICE IS COMPATIBLE WITH TOUCH ID

Now, check if the device is actually compatible with Touch ID. Ask the current authentication context if the policy can be evaluated by pasting this into authenticateUser:

if context.canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, error: &error) {}

Note that we are asking for the biometrics policy type here

DeviceOwnerAuthenticationWithBiometrics

This method takes two parameters:

  • policy: the policy to evaluate, which is the object you created earlier.
  • error: a pointer to an error object, that you will use to inform the user if an error occurs.

 

STEP 5: EVALUATE THE POLICY

If the current context can evaluate the biometrics policy, it means you can finally call the evaluation method within the innermost brackets:

context.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, 
localizedReason: myLocalizedReasonString, 
reply: { (success : Bool, evaluationError : NSError?) -> Void in })

This method takes three parameters:

  • policy: the policy to evaluate.
  • localizedReason: the string to explain the request for user authentication.
  • reply: reply block that is executed when authentication is complete.

 

STEP 6: IMPLEMENT TOUCH ID SUCCESS AND FAILURE CODE

If the authentication succeeded, you can update your UI. To do that, create the following method. You can customize it to do whatever action you need when Touch ID authenticates the user successfully.

func loadData() {
    // Do whatever you want
    println("Load data")
}

Now call it when Touch ID worked (within the reply block)

if success {
    NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
        self.loadData()
    })
}

If the authentication failed with the biometrics policy, you need to handle the error correctly. In this demo app, implement a method to display an alert view with a password field to let the user authenticate with a password if something happen. Keep it empty for now:

func showPasswordAlert() {}

And because the new switch/case implementation is pretty nice in Swift, use it here.

if success {
...
}
else {
    // Authentification failed
    println(evaluationError?.localizedDescription)
 
    switch evaluationError!.code {
        case LAError.SystemCancel.rawValue:
            println("Authentication cancelled by the system")
         case LAError.UserCancel.rawValue:
            println("Authentication cancelled by the user")
         case LAError.UserFallback.rawValue:
            println("User wants to use a password")
            // We show the alert view in the main thread (always update the UI in the main thread)
            NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
                self.showPasswordAlert()
                })
          default:
              println("Authentication failed")
                  NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
                      self.showPasswordAlert()
                      })
          }
}

Here is the list of errors to handle:

  • System cancel
  • User cancel
  • User wants to use a password instead

 

STEP 7: IMPLEMENT ERROR MANAGEMENT FOR POLICY EVALUATION

Same thing for the policy error management. The possibilities are:

  • TouchID not available
  • Passcode not set
if context.canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, error: &error) {
...
    } else {
        switch error!.code {
            case LAError.TouchIDNotEnrolled.rawValue:
                println("TouchID not enrolled")
            case LAError.PasscodeNotSet.rawValue:
                println("Passcode not set")
            default:
                println("TouchID not available")
        }
    self.showPasswordAlert()
}

 

STEP 8: CALL THE METHOD IN VIEWDIDAPPEAR

Now that the method is ready, you can make the call in viewDidAppear.

Note: Why not viewDidLoad? Because you want to make sure the view hierarchy is set up before you present an alert view.
override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    authenticateUser()
}

 

STEP 9: IMPLEMENT A PASSWORD ALERT VIEW WHEN TOUCH ID IS NOT AVAILABLE

It’s time to update the password alert view method. With iOS 8, Apple released a new framework to display alert messages to the user: UIAlertController. This class replaces both UIActionSheet and UIAlertView.

But first things first. Implement a login method that will check if the password is correct. This method takes a String as parameter and either dismiss the alert or present the login alert again if the password is incorrect.

func login(password: String) {
    if password == "weloveprolific" {
        self.loadData()
    } else {
        self.showPasswordAlert()
    }
}

Back to your show password method. Implement a UIAlertController with a title, message and a type.

func showPasswordAlert() {
    // New way to present an alert view using UIAlertController
    let alertController : UIAlertController = 
UIAlertController(title:"TouchID Demo" , message: "Please enter password", preferredStyle: .Alert)
}

You also need to create two UIAlertActions (Cancel and Done actions). These objects will be passed to the UIAlertController. A UIAlertAction object needs a title and a type (here Cancel and Default).

Paste this at the bottom of showPasswordAlert:

// We define the actions to add to the alert controller
let cancelAction : UIAlertAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) -> Void in
    println(action)
}
let doneAction : UIAlertAction = UIAlertAction(title: "Done", style: .Default) { (action) -> Void in
    let passwordTextField = alertController.textFields![0] as UITextField
    self.login(passwordTextField.text)
}
doneAction.enabled = false

In the action block, you defined the action for a button tap. For the cancel action, there is nothing specific to do. But for the done action, you login the user with the text inside the textfield.

Note: The done action is disabled by default because the textfield is empty at the beginning.

The next step is to add an input text field to the controller. To do so, use the method addTextFieldWithConfigurationHandler, and customize the textfield inside the block as a secure entry field. Also, add a notification that fires when the user changes the text inside the field, so you can update the done button.

Do this all at the bottom of showPasswordAlert with this code:

// We are customizing the text field using a configuration handler
alertController.addTextFieldWithConfigurationHandler { (textField) -> Void in
    textField.placeholder = "Password"
    textField.secureTextEntry = true
 
    NSNotificationCenter.defaultCenter().addObserverForName(UITextFieldTextDidChangeNotification, 
object: textField, queue: NSOperationQueue.mainQueue(), usingBlock: { (notification) -> Void in
        doneAction.enabled = textField.text != ""
    })
}

Finally, add your two actions to the controller and present it by pasting this at the bottom of showPasswordAlert:

alertController.addAction(cancelAction)
alertController.addAction(doneAction)
self.presentViewController(alertController, animated: true) {
    // Nothing to do here
}

 

BUILD AND RUN!

Now your app is ready! Build and Run, and you can test out Touch ID with a password fallback!

CONCLUSION

In this tutorial, you implemented the evaluation method to authenticate with user fingerprints with Touch ID. You also reviewed some Swift basic knowledge and the new UIAlertController implementation released with iOS 8. As you can see, it’s very simple to add Touch ID to your projects, as the Local Authentication framework is doing all the work for you. The only thing you have to handle correctly is error management.

In the sample project, I use a Touch ID manager class (both in Swift and Objective-C) that you can directly reuse in your projects. This method is doing the work for you. All you need to do is call it, then put your code in the success and failure blocks.

As you can see, Touch ID is a cool feature, and really easy to implement. It should be considered every time you want to authenticate a user and let them access a sensitive part of your app. People love Touch ID, and will be happy to use it.

 

SUGGESTED FURTHER READING