Touch ID Authentication in the app

Today I am going to write about implementing and using Touch ID authentication in an iOS app. Touch ID authentication API was introduced in iOS 8 release. It is a part of LocalAuthentication framework. The code to include it in your app spans only few lines and easy to integrate.

In order to easily integrate this library in the app I have created a authenticator utility which will do most of the work of authentication and fallback if touch ID mechanism does not exists or not enabled.

Flow of our teeny-tiny app is as follows,

  1. In the beginning user lands on the login page
  2. With given credentials, user is logged into an app
  3. After logging in, user arrives on the view orders page
  4. App provides an interface which allows user to view the previous orders
  5. Since the list previous orders is more sensitive than rest part of the app, we will add one more layer of security before allowing user on this page
  6. When user taps on View Previous Orders page and if touch ID authentication is available, user will be asked to authenticate using fingerprint
  7. If touch ID is unavailable, we will fall back to alternate mechanism and ask user to re-enter the login password

For this demo we're going to use following 3 viewControllers in the order,

  1. LoginPageViewController
  2. ViewOrdersViewController
  3. OrdersViewController

The app flow is as follows,

  1. User opens an app and lands on the login page
  2. After entering credentials, user arrives on page with button to view previous orders
  3. When user presses the button, app asks for touch ID authentication. If that is unavailable, we ask user for an alternate authentication method, that is app password
  4. Once either authentication succeeds, user is taken on the page with the list of previous orders

We will have touch ID authenticator utility in a separate class called TouchIDAuthenticatorUtlity

First off, we will create a protocol named AlertDisplayable. Any class that conform to this protocol will have to implement following two methods


protocol AlertDisplayable {
    func showAlert()
    func authneticationSuccssful()
}

It is important to note that the view controller which is responsible for touch Id authentication will conform to AlertDisplayable protocol to display any error message stemming from incorrect credentials and to proceed with successful login.

Below is an implementation of TouchIDAuthenticatorUtlity


import LocalAuthentication

let defaultUserName = "jdotkawli@gmail.com"
let defaultPassword = "password"

protocol AlertDisplayable {
    func showAlert()
    func authneticationSuccssful()
}

class TouchIDAuthenticatorUtlity {

    let presenter: AlertDisplayable

    init(presenter: AlertDisplayable) {
        self.presenter = presenter
    }

    func authenticateUser() {
        let context = LAContext()
        var error: NSError?
        let reasonString = "Authentication is needed to access orders"

        if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
            context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reasonString, reply: { (success, evalPolicyError) in
                if success {
                    self.presenter.authneticationSuccssful()
                } else {
                    if let error = evalPolicyError as NSError? {
                        switch error.code {

                        case LAError.systemCancel.rawValue:
                            print("Authentication was cancelled by the system")

                        case LAError.userCancel.rawValue:
                            print("Authentication was cancelled by the user")

                        case LAError.userFallback.rawValue:
                            print("User selected to enter custom password")
                            self.presenter.showAlert()
                        default:
                            print("Authentication failed")
                            self.presenter.showAlert()
                        }
                    }
                }
            })
        } else {
            switch error!.code {
            case LAError.touchIDNotEnrolled.rawValue:
                print("TouchID is not enrolled")
            case LAError.passcodeNotSet.rawValue:
                print("A passcode has not been set")
            default:
                print("TouchID not available")
            }
            self.presenter.showAlert()
        }
    }
}

It is important to note that it is necessary to import LocalAuthentication in your project and use the iOS version 8 or more in order to implement the touch ID authentication mechanism

Please also note that when authentication completes, (Either with success or failure), control returns on the background thread. If you want to perform any UI related activities, please make sure to run them explicitly on the main thread

Below is more detailed program flow from the moment user presses View My Previous Orders button


@IBAction func viewPreviousOrdersButtonPressed(_ sender: Any) {
        // authenticateUser method is called when user presses viewPreviousOrdersButtonPressed button
        self.localAuthenticator.authenticateUser()
    }

// As a part of protocol conformance, this viewController implements following methods

// Show error alert in case authentication is unsuccessful
func showAlert() {
    DispatchQueue.main.async {
    // Show Alert
    }
}

// Call this method and move to viewController with list of all previous orders on main thread
func authneticationSuccssful() {
    DispatchQueue.main.async {
        self.moveToOrderList()
    }
}

And this should be it. The project is open sourced and hosted on GitHub if you want to see the full demo with project walkthrough.

Although my design skills are really poor, I am adding some of the fairly ok screenshots from an app below.

login_page
view_orders_page
authentication_dialogue
all_orders_page

Below are some best practices while using touch ID authentication in an app,

  1. Use localized string to explain why you want them to authenticate by themselves
  2. Provide alternate authentication mechanism if touch ID is not available
  3. Touch ID could be absent for various reasons such as passcode is turned off, touch ID is not available, device is pre-iOS 8 etc.
  4. It is good practice to let use know of error occurred during touch ID authentication
  5. When authentication succeeds or fails, it returns the control through block on background thread. It is important to encapsulate subsequent code to run on Main thread.

Reference:

AppCoda.com

Apple Developer Portal

Link to Github demo