AWS Cognito User Pool Authentication Flow on iOS

Rey Jenald Peña
Tigerspike Tokyo Blog
6 min readMay 29, 2020

--

This post describes how to integrated AWS Cognito’s User Pool in an iOS application. This was my first time using this technology so it took some trial and error to get it working. Overall it was a great experience and this is a very great technology to implement in your application.

For this post I will be sharing with you how I implemented the sign-up feature in a step-by-step manner.

Project Specification

For the project that I was working on, we had two specific requirements for the Authentication Module:

  1. Use AWS Cognito
  2. Two-factor Authentication

Two-factor authentication was the challenging part and we would be discussing more of its details on Step-5 of the development process.

Development Process

To be able to successfully implement the sign-up feature we need to do the following steps.

Step-1: S̶e̶t̶u̶p̶ A̶W̶S̶ ̶C̶o̶n̶s̶o̶l̶e
Step-2
: Install AWS Mobile SDK for iOS
Step-3: Configure the UserPoolIdentityProvider
Step-4: Implement Sign-up
Step-5: Implement Two-Factor Authentication

Step-1: AWS Console Setup

I apologize but I won’t be discussing this part in detail. 🙏 But I’ll be sharing with you the key information that I felt was important in understanding the whole setup process in relevance to the client-side implementation.

  • Create Identity Pool
    An identity pool is a store of user identity data specific to your account. You can read more details here.
  • Configure User Pool App Client
    This is an app entity within a User Pool that has permission to call unauthenticated API requests such as; register, sign-in or handle forgotten passwords. You can read more details here.

Client ID + Region

These are the key information that we will be using to make this feature work.

  • App Client ID — This is the unique ID you get after you configure an App Client under a User Pool. You could have different client ID’s for different modules such as; register, sign-up, login, etc.
  • AWS region — where the Identity Pool was created.

Step-2: Install AWS Mobile SDK for iOS

I am a fan of Cocoapods however for this project we were required to use Carthage as our dependency manager.

You can follow the guide on how to set it up under AWS’s SDK Setup Options.

Tip: You don’t need to link all frameworks to the project. You can link only the frameworks we will be using.

Step-3: Configure the UserPoolIdentityProvider

First we configure our IdentityProvider with a provider key and a region.

The provider key can be any string while the region is of type AWSRegionType. The region type should match the type that was set on AWS Console, so you should ask the backend team for the correct region type that was setup.

Just to make the implementation cleaner we created a singleton class for accessing our UserPoolIdentity instance.

Singleton object for your IdentityProvider

Using an Identity provider helps you secure your AWS Account since you won’t need to include the security credentials in your project when you distribute your application and set the credentials provider as Anonymous.

Next we then initialized and configure our singleton class on our AppDelegate

Step-4: Implement Sign-up

Intialize an AWSCognitoIdentityProviderSignUpRequest object. This class allows you to create a request to register a specific user. It requires three (3) parameters to be initialized to be able to create a valid request; clientID, username & password.

Now you may ask “Where do we put our custom parameters?”. Under the sign up request object you will see a userAttributes parameter. This is an array of key-value pairs of type AWSCognitoIdentityUserAttributeType. Here is where you place all your custom key-value pairs such as; name, age, gender, country, etc.

Now we can call the request using the AWSCognitoIdentityProvider we setup on our Cognito Manager singleton.

And that’s it, now you have successfully sent a request to register a user. But since we require two-factor authentication it won’t be registered unless we finish step-5.

Note: For the next step there should be something you need to keep in reference to the user that you just registered. It may be a user-key, user-id, token, secret-key, or any unique string returned by the server

Step-5: Implement Two-Factor Authentication

Due confidentiality I won’t be showing you the exact steps on how we implemented it on our project but instead show you an example on how to use AWS’ User Pool Authentication Flow.

This flow is an additional feature on AWS which, in addition to password, verifies the user’s identity. It is implemented by letting the user answer a single or a series of challenges until either the user fails or receives the token which indicates a successful authentication. You can implement this flow using these two main API calls; InitiateAuth and RespondToAuthChallenge.

However, each project always has its specific needs which the standard flow might now accommodate such as; adding sessions, collecting analytics, requiring custom key-value pairs to be passed, passing sensitive data like fingerprint, location, ip address, etc.

Don’t worry, AWS Cognito got you covered! ;)

For this, we will be using Custom Authentication Flow. This allows us to customize a series of challenges and responses based on the given project requirements.

But first, let’s see how we handle a series of challenges. And what better way to explain it rather than through a visual representation.

Now let’s see some sample codes!!!

Since we will be handling a series of challenges let’s create a struct called CustomChallenge to pass around.

We added a session variable since authentication flows are time constrained and should be done under one active and valid session for security.

Now let’s start the authentication flow by creating our IniateAuth request object which is of type AWSCognitoIdentityProviderInitiateAuthRequest. This class has two (2) required parameters: clientID and authFlow.

Since we will be implementing a custom authentication flow we set authFlow to .customAuth. Then we parse the response and create a challenge object.

Now that we have the challenge object returned from the backend, we now have to respond to this. To do this we call the RespondToAuthChallenge by creating a AWSCognitoIdentityProviderRespondToAuthChallengeRequest object. This class has two (2) required parameters; clientID and challengeName.

The code snippet above shows you how to handle when we are at the final challenge. That is, when the API returns a token which will be under response.authenticationResult.

And also how we handle the next challenge by parsing through the response and getting the challengeName under response.challengeParameters dictionary.

You might be wondering “Why not response.challengeName?”. You might have scrolled back and checked the previous snippet above (InitiateAuth) to double check how we parsed the challenge the first time. To explain, when using RespondToAuthChallenge the challengeName will return the name of the challenge we are responding to. It is understandable since we also need to verify that the response matches the challenge that was addressed..

And there you have it, AWS Cognito’s Authentication Flow implementation. It was really challenging and exciting implementing this feature and I hope this article was of any help to you.

--

--