Authentication Using iOS Keychain

In this tutorial you learn step-by-step how to use the iOS keychain to authenticate the app user’s email and password.

Code presented in this tutorial assume you are using Xcode 7.3 and Swift version 2.2. So if you are using a older or newer version of Swift, it may produce errors. Fix them by using Xcode’s Fix-it tool. Also, I assume you aren’t a newbie to the Swift Programming Language and you know your way around Xcode Integrated Development Editor.

The application you will develop in this tutorial is called KeychainAuthentication. The application has three scenes and each one is connected to a class file. As you can see in the image below, scene 1 is embedded in a Navigation Controller.

Figure 00
Figure 00

I got the KeychainSwiftDistrib class file shown in the project navigator from this GitHub page. You will use its functions in the KeychainAuthentication application’s class files.

What is iOS Keychain?

niftyiap-figure9-3iOS keychain is an encrypted container for storing small pieces of data that needs to be secured. On an iOS device, each application has its own keychain to which only the application has access to it. Data stored in the iOS keychain are safe and unaccessible by other applications. Furthermore, keychain data are stored separately from the application’s bundle. You can think of the iOS keychain as a physical keychain and piece of data stored in it are keys.

Now is a good time to download the tutorial’s starter project and test drive it on your iOS device or the iOS Simulator.

download-excodeproj

Create a New Branch

In the remainder of the tutorial, you’ll be entering code in these class files:

  • RegistrationViewController.swift
  • LoginViewController.swift
  • MainViewController.swift

Before you get started in doing that; I want you to use Xcode’s Source Control ➤ New Branch… command to created a new branch called registration-tasks from the master branch.

xcode-sourcecontrol-fig01

The User Registration Tasks

The Registration View and its class file currently look like the one shown in Figure 01 below. When the user tap the Register button on the Registration View, we want the app to respond by doing the following tasks:

  1. Validate the registration form and display an error message, if any, in an alert view.
  2. Save data in the iOS keychain.
  3. Dismiss the Registration View.
  4. Get data from the iOS keychain and display them in the console.
Figure 01
Figure 01

Click the RegistrationViewController.swift file to load it in Xcode’s Standard editor. Replace the NSLog() statement in the registerButtonTapped() function with these statements; which implement the first user registration task, shown in above list.

@IBAction func registerButtonTapped(sender: AnyObject) {
    if(emailTextField.text.isEmpty == true ||
    passwordOneTextField.text.isEmpty == true ||
    passwordTwoTextField.text.isEmpty == true)
    {
        showAlertView("Fill in all fields")
        return
    } else if(passwordOneTextField.text != passwordTwoTextField.text) {
        showAlertView("Passwords do not match")
        return
    }
}

Code Output

A sample run of the KeychainAuthentication application on the simulator product this alert view on the simulator screen.

Figure 03
Figure 02

What you have to do now is enter code in the registrationButtonTapped() function to implement the second and third user registration task. Start by entering this statements below line 15, in the RegistrationViewController class. It create a keychain object.

let keychain = KeychainSwift()

Next, enter this code below existing code in the registerButtonTapped() function. The last statement dismiss the Registration View. Doing so cause the app to display the LoginViewController’s view on the user’s device screen.

keychain.set(emailTextField.text!, forKey: "userEmail")
keychain.set(passwordOneTextField.text!, forKey: "userPassword")
keychain.setBool(false, forKey: "userLoggedIn")
    
print("Registration successful")
self.dismissViewControllerAnimated(true, completion: nil)
}

Now, run the app on the iPhone simulator and enter the following information in the Registration View’s text fields and click the Register button.

Notice, how the application automatically display the Login View when you click the Register button.

Now, terminate the app and enter code shown below in the RegistrationViewController class’ viewDidLoad() function. It implement the final user registration task.

print("Items in the application's keychain\n-----------------------------------")
print("userEmail: ",keychain.get("userEmail"))
print("userPassword", keychain.get("userPassword"))
print("userLoggedIn", keychain.getBool("userLoggedIn"))
print("-----------------------------------")

Run the app on the simulator and click the Login View’s Register button. You will see the Registration View on the simulator screen and this output in Xcode’s console:

That’s it! You are done with the RegistrationViewController.swift file. Use Xcode’s Source Control  ➤ Commit command to commit changes you made in the RegistrationViewController class, to the Git repository.

Create a New Branch

You will now enter code in the LoginViewController class file. Before you get started in doing that; I want you to use Xcode’s Source Control ➤ New Branch… command to created a new branch called login-tasks from the registration-task branch.

xcode-sourcecontrol-fig01

The User Login Tasks

The Login View and its class file currently look like the one shown in Figure 03 below. When the user tap the Login button on the Login View, we want the app to respond by doing the following tasks:

  1. Check to see if the Login form fields are empty; if they are, display a message in an alert view.
  2. Fetch the email from the iOS keychain and store it in a constant called keychainEmail.
  3. Fetch the password for the iOS keychain and store it in a constant called keychainPassword.
  4. Compare the Login form’s email and password textField value against the email and password fetched from the iOS keychain; if they don’t match, display a message in an alert view. If they match, set the keychain’s userLoggedIn item’s value to true and present the MainViewController’s view.
Figure 03
Figure 03

The first thing you have to do is enter this statements below line 14, in the LoginViewController class. As you already know; it create a keychain object.

let keychain = KeychainSwift()

The second thing you have to do is set the Main View’s Storyboard ID because you’ll be referencing it in code.

keychain-authen-fig06

Here is the code to implement the first user login task. Enter it in the LoginViewController class’ loginButtonTapped() function then run the app in the simulator. When you finish testing the Login button’s code, terminate the app.

@IBAction func loginButtonTapped(sender: AnyObject) {
  if(emailTextField.text.isEmpty == true || passwordTextField.text.isEmpty == true) {
    showAlertView("email and password are required")
    return
  }
}

Here is the code to implement the second, third, and fourth user login tasks. Enter it below code that’s in the loginButtonTapped() function.

let keychainEmail = keychain.get("userEmail")
let keychainPassword = keychain.get("userPassword")
        
if(keychainEmail != emailTextField.text) {
  showAlertView("Sorry, the email you provided doesn't exist in our database")
  return
} else if(keychainPassword != passwordTextField.text) {
  showAlertView("Sorry, the password you provided doesn't exist in our database")
  return

  keychain.set(true, forKey: "userLoggedIn")
    
  let storyBoard:UIStoryboard = UIStoryboard(name:"Main", bundle:nil)
  let nextViewController = storyBoard.instantiateViewControllerWithIdentifier("mainView") as! MainViewController
  self.presentViewController(nextViewController, animated:true, completion:nil)
}

That’s it; you are done with the LoginViewController class. Before you run the app in the simulator, go to the MainViewController class and enter this declaration statement below line 11.

let keychain = KeychainSwift()

Next, enter this code in the MainViewController class’ viewDidAppear() function. The code basically check to see if the user have logged into the app. If not, transport the user to the Login View.

override func viewDidAppear(animated: Bool) {
    if let keychainUserLoggedIn = keychain.getBool("userLoggedIn") {
        if(keychainUserLoggedIn == false) {
            self.performSegueWithIdentifier("loginView", sender: self)
        }
    }
}

Go ahead and run the app in the simulator and you will see the Login View. Enter the email (merlyn@theapplady.net) and the password (1450) you entered in the registration form earlier on and click the Login button. The app respond by logging you into the app and display the Main View.

keychain-authen-fig07a
Figure A: Login View

keychain-authen-fig07b
Figure B: Main View

The reason why you are seeing the Main View is because this statement you entered in the LoginViewController’s loginButtonTapped() function:

keychain.set(true, forKey: "userLoggedIn")

and this code you entered in the MainViewController’s viewDidLoad() function; which check the value of the keychain’s userLoggedIn item:

if let keychainUserLoggedIn = keychain.getBool("userLoggedIn") {
  if(keychainUserLoggedIn == false) {
    self.performSegueWithIdentifier("loginView", sender: self)
  }
}

With that said, terminate the app and run it again in the simulator and you will see the Main View. Click the Log Out button and the app display the Login View. Behind the scene, the app doesn’t actually log you out of the app. So, every time you launch the app, you’ll see the Main View.

You are done with the LoginViewController and the MainViewController class. Use Xcode’s Source Control  ➤ Commit command to commit changes you made in the LoginViewController.swift file and the MainViewController.swift file, to the Git repository.

The User Logout Tasks

The last thing you have to do is enter code in the the MainViewController’s logoutButtonTapped() function to perform these tasks:

  1. Log the user out of the app.
  2. Send the user back to the Login View.

Before you get started in implementing above tasks in the MainViewController class; use Xcode’s Source Control ➤ New Branch… command to created a new branch called logout-tasks from the registration-task branch.

xcode-sourcecontrol-fig01

Now, the logoutButtonTapped() function already contain code to perform the second task in above list. All you have to do is enter code in the function to perform the first task. The logoutButtonTapped() function should look like this now:

@IBAction func logoutButtonTapped(sender: AnyObject) {
  keychain.set(false, forKey:"userLoggedIn")
  self.performSegueWithIdentifier("loginView", sender: self)
}

Now, take the app for a spin in the simulator. When you see the Main View, tap the Log Out button. The app respond by logging you out and transport you back to the Login View. Terminate the app and run it again in the simulator. This time you see the Login View instead of the Main View; that’s because you are no longer logged in to the app.

Every time you run the app on the simulator and click the Register button that’s on the Login View; the app transport you to the Registration View and display the user’s login credentials, in the console. To fix that, go to the RegistrationViewController.swift file and delete the print statements in the viewDidLoad() function. Save changes you made in the file and commit changes in the Git repository.