Front-End Web & Mobile
One-time Password Authentication with the Amplify Libraries for Swift
June 27, 2024: This blog post covers Amplify Gen 1. For new Amplify apps, we recommend using Amplify Gen 2. You can learn more about Gen 2 in our launch blog post.
There are many types of authentication flows for different apps, but using a one-time password (OTP) is one of the more mainstream authentication flows users expect from an app. An OTP flow consist of a user providing either a username or email address and receiving a code (usually 6 digits) via an email or text message.
In this article, you will learn how to create an OTP auth flow for an iOS app using Amazon Simple Email Service (SES) to send an email containing a 6-digit code and authenticate the user using the Auth and Function categories with the AWS Amplify Libraries for Swift.
If you would like to follow along, you can clone the Kilo-Loco/one-time-password-sign-in-amplify-swift repository from GitHub.
Setup Amazon SES
Open the Amazon SES homepage on the AWS Management Console. It is important that you select a region that will match your project. I will be using us-west-2
, but you can choose a different region that may match your existing project or that is aligned with your Amplify CLI profile.
Start by clicking the Create Identity button on the Amazon SES homepage.
Next, create an identity by providing an email address that you can verify. This will be the email address that appears to users in their inbox. It can be changed at a later time, so feel free to use a personal email for testing.
Click Create identity to continue.
If you intend on using a single email address to follow along, it’s important that you use an email address with a service that allows you to send emails to yourself. If your email service doesn’t allow you to email yourself, you will need to create a second identity that you will use to sign up in the app for testing.
You will now see that the Identity status is set to Verification pending.
Open your email and click the link to verify your email address.
The link will take you to a congratulations page that signifies that your email has been verified.
Refresh the Amazon SES Verified identities page and you will see that email address now has an Identity status of Verified.
At this point, your Amazon SES account will still be in sandbox, meaning you will only be able to send emails to verified identities. If you attempt to send emails to (sign up with) non-verified email addresses, the SES will not send out an email.
Setup Amplify Project
I will be using the Amplify CLI to create the Amplify project in the root directory of my iOS project, but you can use Amplify Studio if you’re more comfortable with that.
In the root directory of your Xcode project, run the following command in the terminal:
I will use the default configuration for an iOS project and ensure I use a profile that matches the region of my Amazon SES identity. You can see the values I selected in the following snippet:
Once your Amplify project in successfully created, you must use the Amplify CLI to configure the Auth category since an OTP flow requires a manual configuration.
Enter the following command in the terminal:
Answer the prompts with the following values
Update boilerplate-create-challenge.js
with the following code:
- The
sendChallengeCode
will take the email address that’s provided by the user through the app and uses the AWS SDK to send the secret code from the email address that you verified with SES. - The challenge code will be stored as the answer so when the user receives the challenge code in the email, it can be compared.
- The
publicChallengeParameters
are returned in as a response once the user has provided an email address in the app and triggered the create challenge flow. You can present these values in the app if desired.
Update boilerplate-define-challenge.js
with the following code:
The snippet above will check if the session dictionary is empty or has a single value. Once a session exists, authentication tokens can be issued to the user.
Update boilerplate-verify.js
with the following code:
verifyAuthChallengeResponse
simply checks if the challenge code that was stored during the create challenge function matches the code submitted by the user in the app. It then returns whether the answer is correct or not.
Although you may have finished answering all the prompts of amplify add auth
at this point, you still must make a few more updates to the functions so they work as expected.
The custom policies must be updated to allow emails to be sent out by Amazon SES. Update the custom-policies.json
file (<YOUR_PROJECT>/amplify/backend/function/<project_code>CreateAuthChallenge/custom-policies.json) for the create challenge with the following code:
Additionally, since the a random code is being generated via a third party package during the creation of the auth challenge in boilerplate-create-challenge.js
, you must update the package.json
(<YOUR_PROJECT>/amplify/backend/function/<project_code>CreateAuthChallenge/src/package.json) file for the create challenge to include the dependency.
With the Auth category configured and your functions setup, it’s time to push your configuration to the backend. Run the following command:
The Amplify CLI will show which resources have been created. It should look similar to the snippet below:
If everything looks correct, hit Enter to continue. Once the configuration has been successfully deployed, you will see the following output in the terminal:
Add Amplify as a Dependency
Now it’s time to open Xcode and add Amplify as a dependency for the iOS project. Open the Search Packages screen (File > Add Packages…
):
Enter the Amplify Libraries for Swift repo URL (https://github.com/aws-amplify/amplify-swift/
) in the search bar at the top right. Select Up to Next Major Version for Dependency Rule and set the value to 2.0.0
, then click Add Package.
Select Amplify and AWSCognitoAuthPlugin as the package products and click Add Package.
You will now see Amplify and its dependencies added to the navigation bar in Xcode.
Configure Amplify
If the two configuration files have not been added to your Xcode project, open Finder, navigate to the root directory of your project, then drag and drop both amplifyconfiguration.json
and awsconfiguration.json
into the Xcode Navigation pane.
Open the <YOUR_PROJECT>App.swift
file (one_time_password_sign_in_amplifyApp.swift
if you’re following along from the repo) and add the following import statements to the top:
Inside the <YOUR_PROJECT>App
object, add the following function to configure Amplify:
Add the following init
method to ensure that Amplify is configured as soon as the app is initialized:
Build and run. You will see the following output in the Xcode logs:
Implement Authentication
Finally, you will be implementing the functionality that will allow the user to sign up, confirm sign up, and login using a passwordless flow by using OTP sent via email.
In SignUpView.swift
add the following import statement:
In the SignUpView
object, add the following method to handle sign up:
The sign up process is the same as a typical username authentication flow with one exception, the password is a randomly generated string since a value is required but won’t be used for the user to sign in.
In the body
of SignUpView
, update the sign up button to call signUp
for the action:
In ConfirmSignUpView.swift
add the following import statement at the top:
Add the standard confirm sign up functionality to ConfirmSignUpView
:
Update the confirm sign up button to call confirmSignUp
:
In LoginView.swift
add the following import statements:
Next, add a login function that will trigger the one-time password authentication flow:
- The auth flow type is set to
.customWithoutSRP
which will skip the default SRP (Secure Remote Password) and jump straight into the custom auth flow that was built in our functions. - The
.confirmSignInWithCustomChallenge
case provides additional info which includes information that is provided throughpublicChallengeParameters
of the create challenge function. It also indicates that the custom challenge was a success and the user must move forward and confirm the sign in using the custom challenge.
Update the login button to call login
:
To finish the authentication process, navigate to EmailCodeView.swift
and add the following import statement at the top:
Add a function that will handle the challenge response by entering the code that was emailed to the user:
confirmSignIn
will take the code entered by the user and send it to the verifyAuthChallengeResponse
function where it will then be compared to the code that was sent out via email. If answerCorrect
comes back as true
, the nextStep
will be .done
, indicating that the user has successfully signed in to the app.
Lastly, update the confirm login button to call confirmSignIn
:
Build and run. You will now be able to authenticate a new user using any email addresses that you verified with Amazon SES.
Conclusion
You have successfully setup a custom authentication flow using OTP by using Amazon SES to send a code via email and Amplify Auth to sign in the user without the need for a password. If you’re ready to use this flow in a production app, you will need to request production access on the Amazon SES dashboard so your app can send emails to unverified email addresses. If you don’t plan on maintaining this code, it is recomended that you run amplify delete
to remove all the resources that were generated for you during this tutorial.
As you use Amplify to build your next project, be sure to reach out on the GitHub repository, or through the Amplify Discord server under the #swift-help channel to help us prioritize features and enhancements.