authenticationmigrationamazon-cognitoauth0

Migrate AWS Cognito users to Auth0


I want to move all existing users from an AWS Cognito Pool to Auth0. Preferably with existing passwords or with on-the-fly migration if a password change is must. I see user guides online to migrate Okta/Stormpath etc users to auth0, but not seeing anything for cognito to autho ingegration. Any pointer would be helpful.


Solution

  • There are two ways to import users into Auth0:

    1. Bulk Migration
    2. Automatic Migration (i.e. Lazy Load)

    Currently, there is really no easy way to export users out of AWS Cognito. And even if you did, the exported user profile would not include the user's hashed password so it would require that the user reset their account password once migrated to Auth0 as the identity provider. Not ideal. So bulk migration is kind of out of the question.

    Instead, Automatic Migration is probably the way to go. You must configure a Custom Database in Auth0 and point it to your AWS Cognito user pool and define two scripts: one to get a user and another to login a user.

    AWS doesn't expose these endpoints via an API by default, but they do have similar functions in their amazon-cognito-identity-js npm package (according to Scenario 4 in the documentation).

    Thanks to @yvovandoorn for writing the javascript code, you can use this npm package in the Auth0 Custom Database get-user and login scripts to perform automatic migration. Just make sure you check the Import Users to Auth0 to true under the Custom Database settings.

    get-user.js

    /*
    Requires Auth0 Global Variables to be set - https://auth0.com/docs/rules/configure-global-variables-for-rules
    If testing locally (or not wanting to use Auth0 Global Variables):
    const configuration = {
      "accessKeyId": "your-cognito-access-key",
      "secretAccessKey": "your-cognito-secret-access-key",
      "region": "your-aws-region",
      "UserPoolId": "your-aws-user-pool"
    */
    
    function getUser(username, callback) {
        const userParameters =  ["email", "email_verified", "custom:designation"];
        const AWS = require('aws-sdk@2.593.0');
        AWS.config.update({ "accessKeyId": configuration.accessKeyId, "secretAccessKey": configuration.secretAccessKey, "region": configuration.region });
        const cognito = new AWS.CognitoIdentityServiceProvider();
    
        cognito.adminGetUser({
            UserPoolId: configuration.UserPoolId,
            Username: username
        }, (err, data) => {
            if (err) {
                console.log(err);
                if (err.code === "UserNotFoundException") return callback(null);
                else callback(err);
            }
            else {
                console.log(data);
                if (data.code === "UserNotFoundException") return callback(null);
                else {
                    let profile = {
                        "user_id": data.UserAttributes.find(item=>item.Name==="sub").Value,
                        "username": data.Username,
                    };
                    userParameters.forEach(customParameterName => {
                        profile[customParameterName] = data.UserAttributes.find(item=>item.Name===customParameterName).Value;
                    });
                    return callback(null, profile);
                }
            }
    
        });
    
    }
    

    login.js

    /*
    Read StackOverflow article about potential window issue: https://stackoverflow.com/questions/40219518/aws-cognito-unauthenticated-login-error-window-is-not-defined-js
    
    Requires Auth0 Global Variables to be set - https://auth0.com/docs/rules/configure-global-variables-for-rules
    
    If testing locally (or not wanting to use Auth0 Global Variables):
    const configuration = {
      "ClientId": "your-aws-client-id",
      "UserPoolId": "your-aws-user-pool-id"
    */
    
    function login(username, password, callback) {
        global.fetch = require('node-fetch@2.6.0');
        var AmazonCognitoIdentity = require('amazon-cognito-identity-js@3.0.14');
        var poolData = {
            UserPoolId: configuration.UserPoolId,
            ClientId: configuration.ClientId
    
        };
        var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
    
        var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails({
            Username: username,
            Password: password
        });
        var userData = {
            Username: username,
            Pool: userPool
        };
        var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
        cognitoUser.authenticateUser(authenticationDetails, {
            onSuccess: function (result) {
                //console.log(result);
                var idTokenPayload = result.getIdToken().payload;
                console.log(idTokenPayload);
                var profile = {
                  user_id: idTokenPayload.sub,
                  email: idTokenPayload.email,
                  /* might want to set this to false if you're not validating email addresses */
                  email_verified: true,
                };
                console.log({ result, idTokenPayload, profile });
                callback(null, profile);
            },
            onFailure: (function (err) {
                return callback(new WrongUsernameOrPasswordError(username))
            })
        });
    }