How to create a one-time password authentication flow using Amplify Flutter
AWS Amplify is a set of tools and services that enables mobile and front-end web developers to build secure, scalable full-stack applications powered by AWS. Amplify recently released a new enhancement for the authentication category to allow Flutter developers to set up custom authentication challenges using Amazon Cognito AWS Lambda triggers. This guide shows how to set up a simple one-time password authentication flow.
The following prerequisites are required to follow along with this post:
- Install and configure Amplify CLI
- A Flutter application targeting Flutter SDK >= 2.0.0 (stable version)
- An iOS configuration targeting at least iOS 11.0
- An Android configuration targeting at least Android API level 21 (Android 5.0) or above, and a Kotlin version of 1.5.31 or higher
- A working Amazon Simple Email Service (Amazon SES) resource
Amazon SES is an email platform that lets you send and receive emails using your email addresses and domains. I’ll use it in this tutorial to send a one-time password to the user.
Follow these steps to setup Amazon SES:
1- Open the Amazon SES homepage on the AWS Management Console. Note the AWS region (e.g., us-west-1), as I’ll use it when implementing the logic for sending of the OTP. The Amazon SES homepage URL will look like this: https://us-east-1.console.aws.amazon.com/ses/home#/homepage
2- To send emails, you must setup and verify a sender identity. This can be a domain or an email address. In this tutorial, I’ll use an email. On the Amazon SES homepage, select [Create Identity]. On the next screen, select [Email address] and submit an email that you can access in its inbox (e.g., your own email address), then select [Create Identity].
3 – Amazon SES will create the identity, and its status will be unverified.
4- You’ll get an email with a link to verify it.
5- Select the link, and Amazon SES will verify the email address. Now you’re ready to use it.
I’ll need the Amazon SES region and the Identity email address to implement the logic of sending of the OTP for the next steps. Therefore, make sure to note those details.
Amplify Project Setup
To connect your Flutter app to your AWS account, you must create an Amplify Project using the Amplify Console Afterward, you can pull your Amplify project locally to your development machine to start building the custom authentication flows.
1- On the Amplify console, select New app and then Build an app.
2- Enter an App name, and then select Confirm deployment.
3- The console will set up the Amplify studio and the backend environments for your App. Once ready, you can open the Amplify studio by selecting Launch Studio.
4- On Amplify Studio, copy the local setup command:
5- Navigate to the root folder of your Flutter app and paste then run the local setup command. The command will pull the backend environment into your App.
6- The command will add a new folder named amplify which contains the amplify project and backend details. The command will also add a new dart file (amplifyconfiguration.dart). The App will use this file to know how to reach your provisioned backend resources at runtime. The following image shows the App folder structure on VSCode.
Setting up the Custom Authentication flow
I’ll use the Amplify CLI to add the Authentication category to the Flutter App,
1- Navigate to the root folder of your Flutter app and run the amplify add auth command. Use the Manual Configuration option and make sure to set up the Lambda Triggers as shown in the following:
2- You must add the logic of generating a secure random number and sending it to the user. For that, open the file [<your_flutter_project>/amplify/backend/function/CreateAuthChallenge/src/boilerplate-create-challenge.js] and copy the following code snippet. Make sure to use the Amazon SES region and Identity email that you created above.
3- Add the
crypto-secure-random-digit as a dependency by updating the file [<your_flutter_project>/amplify/backend/function/<project_code>CreateAuthChallenge/src/package.json] as shown in the following:
4- The CreateAuthChallenge function needs a policy allowing for the sending of emails. You can create the policy by adding the following code to the file [<your_flutter_project>/amplify/backend/function/<project_code>CreateAuthChallenge/custom-policies.json]
5- Update the file [<your_flutter_project>/amplify/backend/function/<project_code>DefineAuthChallenge/src/boilerplate-define-challenge.js] as follows to bypass password authentication (Secure Remote Password validation – SRP) and enable the one-time password experience.
The Amplify Auth library always starts with Secure Remote Password (SRP) validation. In the code above, I bypass the SRP validation and return
CUSTOM_CHALLENGE in the first step. In the second step, if
CUSTOM_CHALLENGE returns with
challengeResult == true I recognize the custom auth challenge is successful, and then I tell Amazon Cognito to issue tokens. In the last
else block, I tell Amazon Cognito to fail the authentication flow.
You can update the following code to enforce the Secure Remote Password (SRP) validation and require the user to submit a valid password.
6- Next, I must update the file [<your_flutter_project>/amplify/backend/function/<project_code>VerifyAuthChallengeResponse/src/boilerplate-verify.js] as follows to verify if the response from the user to the custom challenge is valid or not.
7- Run the command
amplify push to create the resources in the cloud.
8- Open the Amplify Studio by running the command
amplify console and select Amplify Studio.
9- Check the Functions option, and you’ll notice the AWS Lambda function that I created using the CLI.
Building the Flutter App
You can use the Amplify Authenticator library to quickly create an authentication flow for the sample App. You can customize it by introducing a widget for the one-time password sign-in and a widget for the custom challenge. Once the user signs in, the App will display the HomePage showing a button for the user to sign out. Follow these steps to create the sample App:
1- Add the Amplify dependencies to the pubspec.yaml:
2- Update the main.dart file to the following:
Note the logic of configuring Amplify for the Auth category:
3- Wrap the
MaterialApp in an
Authenticator widget. Then use the
authenticatorBuilder method to check for the authentication flow steps and determine what experience to present to the customer. For example, the App will display the
customSignInView widget for the signIn step.
4- Introduce a
custom_signIn_view.dart file to create the
CustomSignInView stateless widget, as shown in the following, to present the one-time password sign-in experience where the user must submit their email address.
5- The user can switch to the signup flow from the
CustomSignInView widget using the
NavigateToSignUpButton widget. For that, add the following
6- Create the
CustomConfirmSignInView stateless widget by adding the
custom_confirm_signIn_view.dart as follows. This widget will use the
CreateAuthChallenge trigger to display the Auth Challenge to the user, where they will be required to submit the random code that is emailed to them.
7- The user can navigate back to the signIn view from the
CustomConfirmSignInView widget using the
NavigateToSignInButton widget. Create that by introducing the following
8- The following homepage is where the signed in user can find a button to sign out:
That is all, I now have a Flutter application set up with a simple one-time password authentication flow using Amplify Flutter Authenticator, the Authentication category, and Amazon Cognito Lambda triggers. If you have any feedback, leave a GitHub issue or join our Discord Community!
Now that you’ve finished this walkthrough, You can delete the backend resources to avoid incurring unexpected costs using the command