Add Secure User Accounts
Authentication is often the foundation in most iOS applications. Whether you’re next app is the next Instagram or Facebook, the user needs to be able to open the door to the wonderful universe you create with Sign up and Sign In functions.
In a mobile environment, you’d typically implement this essential function by exposing your user services’ APIs to the app and allowing it to make changes on your server. While this sounds relatively straight forward, there is an elephant in the room — you need to do all you can to protect your user’s security and privacy.
In this tutorial you’ll:
Learn how to deploy your own Ruby on Rails application server on Heroku
Build a Swift application that interacts with the backend server to authenticate your user
Learn the concepts of secure API design and storage
Capture the moment with a selfie
What’s all this about a selfie? Well, you’ll need something practical to work with, and all the cool kids take selfies, so you’ll build an app that lets the user sign-in to your service and upload their selfie. From ducklips to crazy eyes, the user will be able to safely and securely upload and manage a gallery of selfies, all without concern over whether their image will get out to the masses and become the next meme victim on Social.
Here’s a video demoing the app that you’ll build:
Getting Started
First order of business is to set up your Heroku account and deploy the Rails backend for the app to use.
Setting Up Your Rails Application
Start by cloning the railsauth git repository. This is a simple Ruby on Rails app that already includes all the functionality your app needs. You’ll deploy this directly on Heroku, so there’s no need for you to install Ruby on Rails locally.
Open the terminal, which you can find in Applications\Utilities\Terminal, and type:
If you don’t already have git installed on your Mac then you can follow this guide.
Heroku Account Creation
Next, create a Heroku account so you can deploy Rails.
If you have an existing Heroku account and have already installed the Heroku Toolbelt for Mac then you can skip directly to the next section.
Go to heroku.com and click Sign up for free
Enter your email address and click Sign Up
Check your inbox for an email from Heroku and click on the verification link in-order to verify your email.
Enter a password of your choice and click Save to complete the registration process.
Next, download the Heroku Toolbelt for Mac OS X
Locate the heroku-toolbelt.pkg file you just downloaded and double-click it to launch the installer.
When installation has finished you can quit the installer.
Deploying Rails Application on Heroku
Open the Terminal and type:
Enter your Heroku email and password and press Enter. If you’re prompted to create an SSH key, then type Y and press Enter
You’ll see an “Authentication Successful” message on the Terminal. That’s your cue that the basic setup is done and you’re ready to create your first Heroku application.
Type the following into the Terminal:
Take a note of both your Heroku application and git repository urls, which will look like this:
Now it’s back to the Rails application you cloned earlier — you’ve not forgotten about it have you? :]
In the Terminal, change the directory to the railsauth application directory:
Next, add your Heroku repository as a remote branch by using the git repo url you noted when you created the application. Enter the following, but replace the placeholder text with your url:
To deploy the railsauth application on Heroku, type:
If it prompts you to approve the connection to Heroku, simply type yes.
Congratulations! You’ve successfully deployed your Rails app on Heroku. You can verify this by typing:
This will open the application in your browser and you’ll see the friendly message, “Glad to find you here!”
Now enter the following into the Terminal:
This runs a Rails migration which creates the necessary database tables on Heroku.
There are two more steps you need to complete before you can start working on the Swift application.
Configuring Amazon S3 (Simple Storage Service)
You’ll store selfies on Amazon S3 (Simple Storage Service). This is a popular service for developers who need to cheaply store and retrieve files. Web developers often use S3 to store their media assets.
Go to the Amazon Web Service (AWS) Portal and click Create a Free Account
Follow the on-screen instructions to create a free account, and select I am a new user.
Note: You may need to provide your credit card details. Amazon won’t charge you for 12 months, so long as you don’t exceed their Free Tier usage.
The Free Tier is more than sufficient for this tutorial and other basic projects. You can cancel the subscription at any time if you no longer wish to use S3 or any of the other services provided by Amazon.
Next, go to Amazon Web Service (AWS) Portal and click on Sign In.
Click S3 to go to S3 management console:
Click on Create Bucket to create an S3 bucket.
S3 buckets are collections of objects, and you can store any number of objects in your bucket, kind of like a digital bag of holding. It acts much like a folder on your Mac, but it’s more fun to think of it with a mystical twist.
Enter the name of the bucket as yourname-railsauth-assets and choose your region from the drop down. Make sure you take a note of this name. Next, click Create to make an S3 bucket.
Note: Prefix the bucket with your name or username. Buckets on S3 have to be unique across all of S3. You can read more about bucket naming here.
You’ll need to use your AWS security credentials in the Rails application to store selfies on S3.
In the Amazon Web Services Portal click on your name in the top-right corner and choose Security Credentials from the drop down menu.
Expand the Access Keys (Access Key ID and Secret Access Key) section by clicking the +.
Click Create New Access Key.
Click Show Access Key to obtain your Access Key ID and your Secret Key.
Note: Download the key file so you have a backup of the keys. You won’t be able to re-obtain your secret key if you lose it. Hence the need to download and stash it away somewhere safe.
Setting up Heroku Environment Variables
You should always use environment variables to keep your keys secure. Never hard code such things in your application code.
Open the Terminal and set the following variables one by one. Remember to replace the dummy keys with your actual AWS credentials and S3 bucket name:
With that complete, you now need a secret API username and password to protect your API from unwanted access.
Use this random password generator to create a 64-bit password.
Then, create an API username and password by entering the following in the Terminal:
Here’s an example of what this should look like:
About the APIs
Your server is now set up and ready for use, and you have eight API endpoints at the disposal of your Swift app:
Sign Up
Sign In
Get Token
Upload Photo
Get Photos
Delete Photo
Reset Password
Clear Token
The first three endpoints are locked down using HTTP Basic Authentication. The remaining endpoints expect a username and secret token. Without these details, nobody — including you — can access the APIs directly. Also, the temporary token has a time limit.
You encrypt the user’s password with the AES (Advanced Encryption Standard) encryption algorithm.
Refer to the documentation of the API to find out more, including the request and response format.
Getting Started with the Swift Application
You’re all done with the backend setup, so now you get to play around with Swift :]
Start by downloading the starter project for this tutorial.
Open Main.storyboard and you’ll see the user interface; this have been provided to allow you to focus on Swift:
SelfieCollectionViewController is the main view controller and contains a collection view where you’ll display the selfies.
Another key point to know is that each collection view cell contains an image view to display the selfie, and a label to display the caption.
Take a look at viewDidAppear(_:):
Here you check if the user is already logged in, and if they aren’t you prompt the user to Sign in. Specifically, it checks for a userLoggedIn flag in NSUserDefaults.
Note: Although data stored in NSUserDefaults persists across restarts, you should never use it to store any sensitive information like a users email or password. It resides in the apps Library folder which is accessible to anyone with physical access to the device. However, it’s perfectly fine to use it for storing non-sensitive data like preference settings or temporary flags, like you’re doing above.
Build and run. You should see the Sign in view.
Now you’re ready to take the world by storm and build an app that lets your users capture the essence of their very souls with a single tap, by snapping a selfie :]
You’ll need to complete five primary tasks:
Let a user create a new account
Allow a user to sign in to your application
Display selfies that the user has already uploaded
Upload new selfies
Delete old, dated and undesirable selfies. After-all, everyone likes a second chance to make the perfect funny face!
Before you can proceed, you need to spend a little more time working with the server and API details — specifically, you need to update them in your application.
Open HTTPHelper.swift from the Selfie group and update API_AUTH_NAME, API_AUTH_PASSWORD, and BASE_URL with your heroku server details.
Make sure that BASE_URL still has /api at the end.
With the server details updated, you’re now ready to implement the authentication flow!
Sign up and Sign in
Open ViewController.swift. Replace the content of signupBtnTapped(sender:) with the following:
The code here dismissed the keyboard for the text fields, and then validates whether the required parameters are present. It then calls makeSignUpRequest(userName:userEmail:userPassword:) to make a signup request.
Next, you’ll implement makeSignUpRequest(userName:userEmail:userPassword:). Add the following:
Here’s the section-by-section breakdown of the implementation.
Uses the buildRequest(_:method:authType:) method to create an instance of NSMutableURLRequest and sets the necessary HTTP request parameters. buildRequest(_:method:authType:) is a helper method that’s implemented in the HTTPHelper struct.
Encrypt the users password using AES encryption. The block uses the API password as the encryption key.
Creates the JSON request body and sets all the appropriate parameters and values. For sign-up, the request requires the full name, email and encrypted password from the user.
Use sendRequest(_:completion:) from the HTTPHelper struct to create an instance of NSURLSessionDataTask, which makes a request to create a new user on the Rails server. Also, the user will receive an alert when they create a new account, or the request fails.
The above method uses two helper methods which are implemented in HTTPHelper.swift
buildRequest(_:method:authType:)
sendRequest(_:completion:)
Let’s take a look at the implementations of these methods. Open HTTPHelper.swift.
buildRequest(_:method:authType:) creates an instance of NSMutableURLRequest and sets all necessary HTTP parameters for a request.
Creates the instance of NSMutableURLRequest and sets the HTTP method.
Sets the Content-Type to application/json or multipart/form-data. The default Content-Type is application/json, which tells the server that the request body contains JSON data.
Sets the Authorization header to protect your API and user data. For Sign Up, you’re setting a HTTP Basic Authentication header. This is being passed in the 3rd parameter HTTPRequestAuthType.HTTPBasicAuth where you’re creating the HTTP request.
Basic Authentication is the first line of defense against any API attack; it combines your API username and password into a string and encodes it with Base64 to provide another layer of security.
This will deny all access to your API unless the user has the correct username and password.
Note: Despite sounding like it’s secure, Basic Authentication is not the best way secure your API as there are ways to get around it, but it’s more than sufficient in the scope of this tutorial.
sendRequest(_:completion:) creates an NSURLSession task, which is then used to send the request to the server:
Build and run. Once the application launches, tap the Don’t have an account yet? button to create a new account.
Note: Verify your API_AUTH_NAME, API_AUTH_PASSWORD and BASE_URL are set correctly in HTTPHelper.swift if the request fails.
Next, you’ll implement the Sign in functionality, so replace the existing implementation of signinBtnTapped(sender:) with the following:
When all the required parameters are present, the above code calls makeSignInRequest(userEmail:userPassword) to make a sign in request. Next, implement makeSignInRequest(userEmail:userPassword). Add the following:
The code above is almost identical to the implementation of the makeSignUpRequest(userName:userEmail:userPassword:) , except this time when the user successfully signs in to the application, you’ll receive an api_authtoken and authtoken_expiry date.
For all subsequent requests, you need to use the api_authtoken instead of HTTP Basic Authentication.
Implement the following methods that update the userLoggedIn flag in NSUserDefaults and save the API token respectively:
The api_authtoken is sensitive information, so you shouldn’t store it in NSUserDefaults as that would be kind of like putting out a data buffet for a would-be attacker. Hence, the code above stores it in the Keychain.
On iOS, a Keychain is an encrypted container that holds sensitive information. saveApiTokenInKeychain(tokenDict:) uses Keychain service APIs that provide ways to encrypt one or more key-value pairs.
After dismissing the current view, the application displays SelfieCollectionViewController.
Take it for a test drive! Build and run. After successfully signing in, you should see a blank view.
Wait, why is it blank? Shouldn’t you be able to snap a selfie or something?
There’s nothing to do just yet because you’ve not implemented the code to display anything.
Display Existing Selfies
Open SelfieCollectionViewController.swift and replace the existing implementation of viewDidAppear(_:) with the following:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(true)
// check if user is signed in
let defaults = NSUserDefaults.standardUserDefaults()
// is user is not signed in display controller to sign in or sign up
if defaults.objectForKey(<