Cognito User pools – Migrate User Lambda Trigger

Users can be migrated to Cognito User Pools at the time of sign in or during the forgot-password flow. In fact Cognito Trigger – User migration lambda is the tool, that should be used.

However, my company decided to use Amazon Cognito as our authentication service provider. They have more than 40,000 existing users. To add users to user pool, we decided to use Cognito lambda trigger User Migration instead of importing users.

Basic Introduction to Cognito

Cognito provides authentication, authorization, and user management for applications. User pool is one of the two main components of Amazon Cognito. And also, user pools are user directories that provide sign-up and sign-in options for your app users. Users can sign in directly with his credentials, or through social networks such as Facebook, Twitter or Google.

Moreover, you can migrate users from your existing user directory into Amazon Cognito User Pools at the time of sign-in or during the forgot-password flow with this Lambda trigger. Here, I am trying to demonstrate a simple user migration lambda trigger that adds users based on some predefined password

Configuring User Pool Migrate User Lambda

I am assuming that you are already familiar with Dotnet core 2.2, AWS Lambda Functions, Amazon Cognito, User Pool, and Cognito Triggers.

Basically, you can use AWS Lambda triggers to customize workflows and the user experience with Amazon Cognito. And also, Cognito passes event information to your Lambda function which returns the same event object back to Amazon Cognito with any changes in the response.

User Pool Lambda Triggers

A user migration Lambda trigger allows easy migration of users from your existing user management system into the Cognito user pool. In addition, according to AWS Documentation

Amazon Cognito invokes this trigger when a user does not exist in the user pool at the time of sign-in with a password, or in the forgot-password flow. After the Lambda function returns successfully, Amazon Cognito creates the user in the user pool.

Migrate User Lambda Trigger

I am using C# dotnet core 2.2 to build Amazon Lambda Function that will be triggered when user sign-in

Migrate User Lambda in C#

First, you need create a dotnet core 2.2 project. Add following two packages

  1. Amazon.Lambda.Core
  2. Amazon.Lambda.Serialization.Json

Second, Add a Function class, and the class must contain the FunctionHandler method. The assembly should be serialized with LambdaSerializer. Find an example below.

[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))] 
namespace LambdaUserMigration {
     public class Function {
         public JObject FunctionHandler(JObject input, ILambdaContext context){
             var response = input;
             var userName = input["userName"]?.ToString();
             var password = input["request"]["password"]?.ToString();
             if (!string.IsNullOrWhiteSpace(userName) &&  password == "UserMigration"){
                     response["response"]["userAttributes"] = 
                       JToken.FromObject(new Dictionary<string, object>()              {
                         {"username", userName},
                         {"email", userName},
                         {"email_verified", true}
                      }); 
                     response["response"]["forceAliasCreation"] = false;
                     response["response"]["finalUserStatus"] = "CONFIRMED";
                     response["response"]["messageAction"] = "SUPPRESS";
                     response["response"]["desiredDeliveryMediums"] = JArray.FromObject(new[] {"EMAIL"} );
            }
            return response;
        }
    }
}

Parameter – Datatype JObject

The function has two parameters. And the first one is JObject which is basically the triggered event passed by Cognito. As I mentioned above, you need to send the same event back as the response, for this reason, I copy the input as values as a response and modified its properties if the request is valid, otherwise, I will return the request as a response. Please find the full event below

{
     "userName": "string",
     "request": {
         "password": "string"
     }, 
     "response": {
     "userAttributes": {
         "string": "string",
         …
     },
     "finalUserStatus": "string",
     "messageAction": "string",
     "desiredDeliveryMediums": [ "string", … ],
     "forceAliasCreation": boolean
 }

userAttributes

A mandatory field that contains at least one name-value pairs representing user attributes. As this will be stored in the user profile in the user pool.

finalUserStatus

During sign-in, this attribute can be set to CONFIRMED, or not set, to auto-confirm your users and allow them to sign-in with their previous passwords. This is the simplest experience for the user.
If this attribute is set to RESET_REQUIRED, the user is required to change his or her password immediately after migration at the time of sign-in, and your client app needs to handle thePasswordResetRequiredException during the authentication flow.

finalUserStatus – AWS Documentation

forceAliasCreation

You can set true or false.

  • The phone number or email address specified in the UserAttributes parameter already exists as an alias with a different user and the value assigned is true then the API call will migrate the alias from the previous user to the newly created user. The previous user will no longer be able to log in using that alias.
  • Setting “false” will return an error to the client app if the user already exists.
  • If this attribute is not included in the response, it will consider as “false”.

desiredDeliveryMediums

This will define how the user will get a welcome message. Accepted values are EMAIL or SMS. If this is not added to the response it will use SMS

These are few important attributes for a response from User Migration Lambda Trigger

Add to User Pool

So lets add a user pool Lambda trigger with the console

  • To start with, you can upload the c# dotnet core lambda function using the Lambda console in order to know how please find one of my earlier posts Deploy a simple AWS C# Lambda
  • Now, hook up the Lambda function to the “migrate trigger” in Cognito from Amazon Cognito console
    • Select Manage User Pools.
    • Choose an existing user pool from the list, or create a user pool
    • In your user pool, choose the Triggers tab from the navigation bar.
    • Choose a User Migration Lambda trigger and choose your Lambda function from the Lambda function drop-down list.
    • Choose Save changes.

Now time to test your lambda

Misc

Finally, some miscellaneous information that i found helpful.

Migrate User Lambda Trigger Sources are

  • UserMigration_Authentication – User migration at the time of sign in.
  • UserMigration_ForgotPassword – User migration during forgot-password flow.

Moreover, If any error occurs during migration, the apps will get error responses from the Amazon Cognito User Pools API, and the user might or might not have been created in your user pool.

Your app sends the username and password to Amazon Cognito. If your app has a native sign-in UI and uses the Cognito Identity Provider SDK, your app must use the USER_PASSWORD_AUTH flow, in which the SDK sends the password to the server (your app must not use the default USER_SRP_AUTH flow since the SDK does not send the password to the server in the SRP authentication flow). The USER_PASSWORD_AUTH flow is enabled by setting AuthenticationDetails.authenticationType to “USER_PASSWORD”.

Second Steps during sign-in

So when you are sending sign-in request to Cognito use USER_PASSWORD_AUTH from AWS SDK and select “USER_PASSWORD” authentication type, if not the trigger will not fire. When you use admin authentication flow user migration lambda won‘t trigger

Furthermore, you can download a sample migrate user lambda trigger from my github repository The solution also contains three other cognito lambda triggers for custom authentication process.

Read More about user migration

I recommend to go through the following to AWS documentation to understand more about migration users to user pool

You can read about the user pool triggers here. To know about other lambda triggers please check User Pool Lambda Trigger Sources

I would like to hear your thoughts