2015-02-03

Learn how to secure your app using Touch ID

Protecting an app with a login screen is a great way to secure user data – you can use the Keychain, which is built right in to iOS, to ensure that their data stays secure. However, Apple now offers yet another layer of protection with Touch ID, available on the iPhone 5s, 6, 6+, iPad Air 2, and iPad mini 3.

And if that weren’t enough, with the introduction of extensions in iOS 8, you can even integrate the storage and retrieval of login information using the award-winning 1Password app from AgileBits, thanks to their developers open-sourcing their extension. This means you can comfortably hand over the responsibility of handling login information to the Keychain, TouchID, or 1Password!

In this tutorial you’ll start out using the Keychain to store and verify login information. After that, you’ll explore Touch ID and then finish off by integrating the 1Password extension into your app.

Note: Touch ID and 1Password require you test on a physical device, but the Keychain can be used in the simulator

Getting Started

Please download the starter project for this tutorial here.

This is a basic note taking app that uses Core Data to store user notes; the storyboard has a login view where users can enter a username and password, and the rest of the app’s views are already connected to each other and ready to use.

Build and run to see what your app looks like in its current state:

At this point, tapping the Login button simply dismisses the view and displays a list of notes – you can also create new notes from this screen. Tapping Logout takes you back the login view. If the app is pushed to the background it will immediately return to the login view; this protects data from being viewed without being logged in. This is controlled by setting Application does not run in background to YES in Info.plist.

Before you do anything else, you should change the Bundle Identifier, and assign an appropriate Team.

Select TouchMeIn in the Project Navigator, and then select the TouchMeIn target. In the General tab change Bundle Identifier to use your own domain name, in reverse-domain-notation – for example com.raywenderich.TouchMeIn.

Then, from the Team menu, select the team associated with your developer account like so:

With all of the housekeeping done, it’s time to code! :]

Logging? No. Log In.

To get the ball rolling, you’re going to add the ability to check the user-provided credentials against hard-coded values.

Open LoginViewController.swift and add the following constants just below where the managedObjectContext variable is declared:

These are simply the hard-coded username and password you’ll be checking the user-provided credentials against.

Add the following function below loginAction(_:):

This checks the user-provided credentials against the constants you defined earlier.

Next, replace the contents of loginAction(_:) with the following:

This calls checkLogin(_:password:), which dismisses the login view if the credentials are correct.

Build and run. Enter the username batman and the password Hello Bruce!, and tap the Login button. The login screen should dismiss as expected.

While this simple approach to authentication seems to work, it’s not terribly secure, as credentials stored as strings can easily be compromised by curious hackers with the right tools and training. As a best practice, passwords should NEVER be stored directly in the app.

To that end, you’ll employ the Keychain to store the password. Check out Chris Lowe’s Basic Security in iOS 5 – Part 1 tutorial for the lowdown on how the Keychain works.

The next step is to add a Keychain wrapper class to your app, however it’s in Objective-C, so you’ll also need to add a bridging header to be able to access the Objective-C class from within Swift.

Rapper? No. Wrapper.

You can download KeychainWrapper here; this wrapper comes from Apple’s Keychain Services Programming Guide.

Once downloaded, unzip the archive and drag KeychainWrapper.h and KeychainWrapper.m into the project, like so:

When prompted, make sure that Copy items if needed is checked and the TouchMeIn target is checked as well:

Since you’re adding an Objective-C file to a Swift project, Xcode will offer to create the bridging header file – click Yes:

This creates a bridging header named TouchMeIn-Bridging-Header.h. You’ll add the Objective-C headers to this file so they can be accessed by your Swift app.

To check that the bridging header is properly setup, select TouchMeIn in the Project Navigator. Then navigate to the Build Settings. In the search bar, enter Swift Compiler, then locate the Objective-C Bridging Header field, which should now contain TouchMeIn/TouchMeIn-Bridging-Header.h, as shown below:

Note: You can read more about Bridging Headers in Porting Your App to the iPhone 6, iPhone 6 Plus and iOS 8: Top 10 Tips. To learn more about using Swift and Objective-C together, have a look at Apple’s Using Swift with Cocoa and Objective-C guide.

Open TouchMeIn-Bridging-Header.h and import the Keychain wrapper at the top of the file:

Build and run to make sure you have no errors. All good? Great — now you can leverage the Keychain from within your app.

Note: If you do see some errors then please refer to Apple’s Using Swift with Cocoa and Objective-C guide for help on how to get them resolved.

Keychain, Meet Password. Password, Meet Keychain

To use the Keychain, you first need to store a username and password. After that, you check the user-provided credentials against the Keychain to see if they match.

You’ll need to track whether the user has already created some credentials so that you can change the text on the Login button from “Create” to “Login”. You’ll also store the username in the user defaults so you can perform this check without hitting the Keychain each time.

Open up LoginViewController.swift and delete the following lines:

In their place, add the following:

MyKeychainWrapper holds a reference to the Objective-C KeychainWrapper class. The next two constants will be used to determine if the Login button is being used to create some credentials, or to log in; the loginButton outlet will be used to update the title of the button depending on that same state.

Open Main.storyboard and Ctrl-drag from the Login View Controller to the Login button, as shown below:

From the resulting popup, choose loginButton:

Next, you need to handle the following two cases for when the button is tapped: if the user hasn’t yet created their credentials, the button text will show “Create”, otherwise the button will show “Login”. You also need to check the entered credentials against the Keychain.

Open LoginViewController.swift and replace the code in loginAction(_:) with the following:

Here’s what’s happening in the code:

If either the username or password is empty, then present an alert to the user and return from the method.

Dismiss the keyboard if it’s visible.

If the login button’s tag is createLoginButtonTag, then proceed to create a new login.

Next, you read hasLoginKey from NSUserDefaults which indicates whether a password has been saved to the Keychain. If the username field is not empty and hasLoginKey indicates no login has already been saved, then you save the username to NSUserDefaults.

You then use mySetObject and writeToKeychain to save the password text to Keychain. You then set hasLoginKey in NSUserDefaults to true to indicate that a password has been saved to the keychain. You set the login button’s tag to loginButtonTag so that it will prompt the user to log in the next time they run your app, rather than prompting the user to create a login. Finally, you dismiss loginView.

If the user is logging in (as indicated by loginButtonTag), you call checkLogin(_:password:) to verify the user-provided credentials; if they match then you dismiss the login view.

If the login authentication fails, then present an alert message to the user.

Note: Why not just store the password along with the username in NSUserDefaults? That would be a bad idea because values stored in NSUserDefaults are persisted using a plist file. This is essentially an XML file that resides in the app’s Library folder, and is therefore readable by anyone with physical access to the device. The Keychain, on the other hand, uses the Triple Digital Encryption Standard (3DES) to encrypt its data.

Next, replace the implementation of checkLogin(_:password:) with the following:

This checks that the username entered matches the one stored in NSUserDefaults and that the password matches the one stored in the Keychain.

Now you need to set the button title and tags appropriately depending on the state of hasLoginKey.

Add the following to viewDidLoad(), just below the call to super:

Taking each numbered comment in turn:

You first check hasLoginKey to see if you’ve already stored a login for this user.

If so, change the button’s title to Login, update its tag to loginButtonTag, and hide createInfoLabel, which contains the informative text “Start by creating a username and password“. If you don’t have a stored login for this user, set the button label to Create and display createInfoLabel to the user.

Finally, you set the username field to what is saved in NSUserDefaults to make logging in a little more convenient for the user.

Build and run. Enter a username and password of your own choosing, then tap Create.

Note: If you forgot to connect the loginButton IBOutlet then you might see the error Fatal error: unexpectedly found nil while unwrapping an Optional value”. If you do, connect the outlet as described in the relevant step above.

Now tap Logout and attempt to login with the same username and password – you should see the list of notes appear.

Tap Logout and try to log in again – this time, use a different password and then tap Login. You should see the following alert:

Congratulations – you’ve now added authentication use the Keychain. Next up, Touch ID.

Touching You, Touching Me

Note: In order to test Touch ID, you’ll need to run the app on a physical device that supports Touch ID. At the time of this writing, that includes the iPhone 5s, 6, 6+, and iPad Air 2 and iPad mini 3.

In this section, you’ll add Touch ID to your project in addition to using the Keychain. While Keychain isn’t necessary for Touch ID to work, it’s always a good idea to implement a backup authentication method for instances where Touch ID fails, or for users that don’t have a Touch ID compatible device.

Open Images.xcassets.

Download the images assets for this part of the project here. Unzip them and open the resulting folder. Locate Touch-icon-lg.png, Touch-icon-lg@2x.png, and Touch-icon-lg@3x.png, select all three and drag them into Images.xcassets so that Xcode they’re the same image, only with different resolutions:

Open up Main.storyboard and drag a Button from the Object Library onto the Login View Controller Scene, just below the label.

Use the Attributes Inspector to adjust the button’s attributes as follows:

Set Type to Custom.

Leave the Title empty.

Set Image to Touch-icon-lg.

When you’re done, the button’s attributes should look like this:

Now adjust your button in the Size Inspector as shown below:

Show should be Frame Rectangle

X should be 267

Y should be 341

Width should be 67

Height should be 66

When you’re done, the Size Inspector should look like the following:

Ensure your new button is selected, then click the pin button in the layout bar at the foot of the storyboard canvas and set the constraints as below:

Top Space should be 16.5

Width should be 67

Height should be 67

Next, click the align button and check Horizontal Center in Container:

Finally, click the Resolve Auto Layout Issues icon and select Selected Views\Update Frames, as shown below:

This updates the button’s frame to match its new constraints.

Your view should now look like the following:

Still in Main.storyboard, open the Assistant Editor and make sure LoginViewController.swift is showing.

Now, Ctrl-drag from the button you just added to LoginViewController.swift, just below the other properties, like so:

In the popup enter touchIDButton as the Name and click Connect:

This creates an outlet that you will use to hide the button on devices that don’t have Touch ID available.

Now you need to add an action for the button.

Ctrl-drag from the same button to LoginViewController.swift to just above checkLogin(_:password:):

In the popup, change Connection to Action, set Name to touchIDLoginAction, and click Connect.

Build and run to check for any errors. You can still build for the Simulator at this point since you haven’t yet added support for Touch ID. You’ll take care of that now.

Adding Local Authentication

Implementing Touch ID is as simple as importing the Local Authentication framework and calling a couple of simple yet powerful methods.

Here’s what the documentation the Local Authentication documentation has to say:

“The Local Authentication framework provides facilities for requesting authentication from users with specified security policies.”

The specified security policy in this case will be your user’s biometrics — A.K.A their fingerprint! :]

Open up LoginViewController.swift and add the following import, just below the CoreData import:

Now you’ll need a reference to the LAContext class, as well as an error property.

Add the following code below the rest of your properties:

You will use error in a few places later on in this tutorial; context references an authentication context, which is the main player in Local Authentication.

At the bottom of viewDidLoad() add the following:

Here you use canEvaluatePolicy(_:error:) to check whether the device can implement Touch ID authentication. If so, then show the Touch ID button; if not, then leave it hidden.

Build and run on the Simulator; you’ll see the Touch ID logo is hidden. Now build and run on your physical Touch ID-capable device; you’ll see the Touch ID button is displayed.

Putting Touch ID to Work

Still working in LoginViewController.swift, replace the entire touchIDLoginAction(_:) method with the following:

Here’s what’s going on in the code above:

Once again, you’re using canEvaluatePolicy(_:error:) to check whether the device is Touch ID capable.

If the device does support Touch ID, you then use evaluatePolicy(_:localizedReason:reply:) to begin the policy evaluation — that is, prompt the user for Touch ID authentication. evaluatePolicy(_:localizedReason:reply:) takes a reply block that is executed after the evaluation completes.

Inside the reply block, you handling the success case first. By default, the policy evaluation happens on a private thread, so your code jumps back to the main thread so it can update the UI. If the authentication was successful, you call the segue that dismisses the login view.

Now for the “failure” cases. You use a switch statement to set appropriate error messages for each error case, then present the user with an alert view.

If canEvaluatePolicy(_:error:) failed, you display a generic alert. In practice, you should really evaluate and address the specific error code returned, which could include any of the following:

LAErrorTouchIDNotAvailable: the device isn’t Touch ID-compatible.

LAErrorPasscodeNotSet: there is no passcode enabled as required for Touch ID

LAErrorTouchIDNotEnrolled: there are no fingerprints stored.

iOS responds to LAErrorPasscodeNotSet and LAErrorTouchIDNotEnrolled on its own with relevant alerts.

Build and run on a physical device and test logging in with Touch ID.

Since LAContext handles most of the heavy lifting, it turned out to be relatively straight forward to implement Touch ID. As a bonus, you were able to have Keychain and Touch ID authentication in the same app, to handle the event that your user doesn’t have a Touch ID-enabled device.

In the third and final part of this tutorial, you’ll use 1Password’s iOS 8 extension to store and retrieve login information, along with other sensitive user data.

1Password To Rule Them All

The password manager 1Password from Agilebits runs on iOS, OS X, Windows, and Android. It stores login credentials, software licenses and other sensitive information in a virtual vault locked with a PBKDF2-encrypted master password. In this section, you’ll learn how to store user credentials in 1Password via the extension, and later retrieve them in order to authenticate a user.

Note: You’ll need 1Password installed on a physical device in order to follow along with the next section.

To begin with, you need to add some new graphics that will be used with a 1Password-specific button.

Open Images.xcassets. Then, amongst the assets you downloaded earlier, locate the following three files:

onepassword-button.png

onepassword-button@2x.png

onepassword-button@3x.png

Select them all and drag them as one into Images.xcassets. Then, find the three files:

onepassword-button-green.png

onepassword-button-green@2x.png

onepassword-button-green@3x.png

And again, select them all and drag them as one into Images.xcassets.

Open Main.storyboard and drag a Button from the Object Library on to the Login View Controller Scene, just below the Touch ID button. Using the Attributes Inspector, adjust the button’s attributes as follows:

Set Type to Custom

Leave Title empty

Set Image to onepassword-button

The Attributes Inspector should now look like the following:

Using the Size Inspector, adjust the placement and size as per the following:

Set X to 287

Set Y to 426

Set Width to 27

Set Height to 33

You can check your size and placement against the image below:

With the button still selected, click pin in the layout bar at the bottom of the storyboard canvas and set the button’s Top Space to 21, Width to 27, and Height to 33:

Next, click align in the layout bar and check Horizontal Center in Container:

Still working with Main.storyboard, open the Assistant Editor, which itself should open up LoginViewController.swift – if it doesn’t, select the file from the jump-bar. Now Ctrl-drag from the button to LoginViewController.swift, just below the other properties, as shown below:

Enter onepasswordSigninButton as the Name in the popup and click Connect:

This creates an IBOutlet that you will use to change the 1Password button image depending on whether it’s available or not.

Next, add an action for onepasswordSigninButton. Ctrl-drag from the button to LoginViewController.swift, just above checkLogin(_:password:):

Change the Connection type to Action. Set the Name to canUse1Password and leave Arguments set to Sender and click Connect.

Build and run. You should see your new 1Password button displayed, as shown below:

An Agile Extension

Now that the interface is laid out, you can start implementing the 1Password support.

Head to the 1Password Extension repository on GitHub and click Download ZIP, as indicated below:

Unzip the downloaded file. Open the folder and drag the OnePasswordExtension.h and OnePasswordExtension.m files into your project, like so:

Make sure that Copy items if needed and the TouchMeIn target are both checked.

Recall that when you add Objective-C files to a Swift project, Xcode offers to make a bridging header. Since you’ve already created a bridging header in an earlier step you can simply add the 1Password header to that.

Open TouchMeIn-Bridging-Header.h and add the following import:

Open LoginViewController.swift and add the following import to the top of the file:

This simply imports the Security framework, which is required by the 1Password extension.

Now add the following properties to the top of LoginViewController:

The former holds a reference to the main class of the 1Password extension, and the latter tracks whether a 1Password record has already been created; you set it to default as false as there won’t be one on first run.

Next update viewDidLoad() by replacing the entire if haslogin block with the following:

This disables the onepasswordSigninButton until the initial username and password have been stored in the Keychain.

Now you’ll need to access the 1Password Extension and test whether the iOS app is installed and available, and enable the 1Password button if it is.

Add the following to viewDidLoad():

This hides onepasswordSigninButton by default, and then shows it only if the extension is installed. You then set has1Password from the has1PassLogin key stored in NSUserDefaults to indicate whether a 1Password record has already been created, and set the button image accordingly.

Next, modify canUse1Password to output a simple message to the console when you tap the 1Password button:

Build and run your app on both the simulator and your physical device with 1Password installed. The 1Password button should be hidden on the simulator, and it should show in green on your physical device. Tap the 1Password button and the following should print to the console:

Tapping into the Power of 1Password

There are a few methods you’ll use in the 1Password extension: storeLoginForURLString(_:loginDetails:passwordGenerationOptions:forViewController:sender:) lets you create some login credentials, while findLoginForURLString(_:forViewController:sender:completion:) retrieves the credentials from the 1Password vault.

Open LoginViewController.swift, and add the following new method to it:

func saveLoginTo1Password(sender: AnyObject) {
// 1.
var newLoginDetails : NSDictionary = [
AppExtensionTitleKey: "Touch Me In",
AppExtensionUsernameKey: usernameTextField.text,
AppExtensionPasswordKey<span

Show more