title: AWS cognito user migration pool trigger not working on login flow
body: <p>I am using AWS cognito pool migration using Lambda function with cognito execution role
  Following is my new pool app client setting  </p>
  
  <p><a href="https://i.stack.imgur.com/KisjI.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/KisjI.png" alt="enter image description here"></a></p>
  
  <p>or </p>
  
  <p><a href="https://i.stack.imgur.com/8C2AZ.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/8C2AZ.png" alt="enter image description here"></a>
  AWS doc says </p>
  
  <blockquote>
    <p>User migration authentication flow A user migration Lambda trigger
    allows easy migration of users from a legacy user management system
    into your user pool. To avoid making your users reset their passwords
    during user migration, choose the USER_PASSWORD_AUTH authentication
    flow. This flow sends your users' passwords to the service over an
    encrypted SSL connection during authentication.</p>
    
    <p>When you have completed migrating all your users, we recommend
    switching flows to the more secure SRP flow. The SRP flow does not
    send any passwords over the network.</p>
  </blockquote>
  
  <p>I have created lambda function with role "AmazonCognitoPowerUser"</p>
  
  <pre><code>        async function authenticateUser(cognitoISP: CognitoIdentityServiceProvider, username: string, password: string): Promise&lt;User | undefined&gt; {
              console.log(`authenticateUser: user='${username}'`);
  
              const params: AdminInitiateAuthRequest = {
                  AuthFlow: 'ADMIN_USER_PASSWORD_AUTH',
                  AuthParameters: {
                      PASSWORD: password,
                      USERNAME: username,
                  },
                  ClientId: OLD_CLIENT_ID,
                  UserPoolId: OLD_USER_POOL_ID,
              };
              const cognitoResponse = await cognitoISP.adminInitiateAuth(params).promise();
              const awsError: AWSError = cognitoResponse as any as AWSError;
              if (awsError.code &amp;&amp; awsError.message) {
                  console.log(`authenticateUser: error ${JSON.stringify(awsError)}`);
                  return undefined;
              }
              console.log(`authenticateUser: found ${JSON.stringify(cognitoResponse)}`);
  
              return lookupUser(cognitoISP, username);
          }
  
          async function lookupUser(cognitoISP: CognitoIdentityServiceProvider, username: string): Promise&lt;User | undefined&gt; {
              console.log(`lookupUser: user='${username}'`);
              const params = {
                  UserPoolId: OLD_USER_POOL_ID,
                  Username: username,
              };
              const cognitoResponse = await cognitoISP.adminGetUser(params).promise();
              const awsError: AWSError = cognitoResponse as any as AWSError;
              if (awsError.code &amp;&amp; awsError.message) {
                  console.log(`lookupUser: error ${JSON.stringify(awsError)}`);
                  return undefined;
              }
              console.log(`lookupUser: found ${JSON.stringify(cognitoResponse)}`);
  
              const userAttributes = cognitoResponse.UserAttributes ? cognitoResponse.UserAttributes.reduce((acc, entry) =&gt; ({
                  ...acc,
                  [entry.Name]: entry.Value,
              }), {} as {[key: string]: string | undefined}) : {};
              const user: User = {
                  userAttributes,
                  userName: cognitoResponse.Username,
              };
              console.log(`lookupUser: response ${JSON.stringify(user)}`);
              return user;
          }
  
          async function onUserMigrationAuthentication(cognitoISP: CognitoIdentityServiceProvider, event: CognitoUserPoolTriggerEvent) {
              // authenticate the user with your existing user directory service
              const user = await authenticateUser(cognitoISP, event.userName!, event.request.password!);
              if (!user) {
                  throw new Error('Bad credentials');
              }
  
              event.response.userAttributes = {
                  // old_username: user.userName,
                  // 'custom:tenant': user.userAttributes['custom:tenant'],
                  email: user.userAttributes.email!,
                  email_verified: 'true',
                  preferred_username: user.userAttributes.preferred_username!,
              };
              event.response.finalUserStatus = 'CONFIRMED';
              event.response.messageAction = 'SUPPRESS';
  
              console.log(`Authentication - response: ${JSON.stringify(event.response)}`);
              return event;
          }
  
          async function onUserMigrationForgotPassword(cognitoISP: CognitoIdentityServiceProvider, event: CognitoUserPoolTriggerEvent) {
              // Lookup the user in your existing user directory service
              const user = await lookupUser(cognitoISP, event.userName!);
              if (!user) {
                  throw new Error('Bad credentials');
              }
  
              event.response.userAttributes = {
                  // old_username: user.userName,
                  // 'custom:tenant': user.userAttributes['custom:tenant'],
                  email: user.userAttributes.email!,
                  email_verified: 'true',
                  preferred_username: user.userAttributes.preferred_username!,
              };
              event.response.messageAction = 'SUPPRESS';
  
              console.log(`Forgot password - response: ${JSON.stringify(event.response)}`);
  
              return event;
          }
  
          export const handler = async (event: CognitoUserPoolTriggerEvent, context: Context): Promise&lt;CognitoUserPoolTriggerEvent&gt; =&gt; {
              const options: CognitoIdentityServiceProvider.Types.ClientConfiguration = {
                  region: OLD_USER_POOL_REGION,
              };
              if (OLD_ROLE_ARN) {
                  options.credentials = new ChainableTemporaryCredentials({
                      params: {
                          ExternalId: OLD_EXTERNAL_ID,
                          RoleArn: OLD_ROLE_ARN,
                          RoleSessionName: context.awsRequestId,
                      },
                  });
              }
              const cognitoIdentityServiceProvider = new CognitoIdentityServiceProvider(options);
  
              switch (event.triggerSource) {
                  case 'UserMigration_Authentication':
                      return onUserMigrationAuthentication(cognitoIdentityServiceProvider, event);
                  case 'UserMigration_ForgotPassword':
                      return onUserMigrationForgotPassword(cognitoIdentityServiceProvider, event);
                  default:
                      throw new Error(`Bad triggerSource ${event.triggerSource}`);
              }
          }
  </code></pre>
  
  <p>and added trigger into new pool,</p>
  
  <p><a href="https://i.stack.imgur.com/fIcTL.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/fIcTL.png" alt="enter image description here"></a></p>
  
  <p><strong>After many attempt Lambda trigger is not working on login always getting error  .</strong> </p>
  
  <pre><code>  {__type: "NotAuthorizedException", message: "Incorrect username or password."}
         message: "Incorrect username or password."
       __type: "NotAuthorizedException"
  </code></pre>
  
  <p><strong>Though its working fine if we use forget passwords flow after reset password user migrated to new pool</strong></p>
  
  <ul>
  <li><a href="https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-import-using-lambda.html" rel="nofollow noreferrer">https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-import-using-lambda.html</a></li>
  </ul>
  
  <p><strong>UPDATED :</strong></p>
  
  <p>When directly run test on lambda using following json</p>
  
  <pre><code>  {
     "version": "1",
     "triggerSource": "UserMigration_Authentication",
     "region": "ap-south-1",
     "userPoolId": "ap-XXXXXXXXX2",
     "userName": "vaquar.test@gmail.com",
     "callerContext": {
     "awsSdkVersion": "aws-sdk-unknown-unknown",
     "clientId": "1XXXXXXXXXXXXXXXXXXfgk"
     },
     "request": {
     "password": "vkhan",
     "validationData": null,
     "userAttributes": null
      },
     "response": {
      "userAttributes": null,
      "forceAliasCreation": null,
      "finalUserStatus": null,
      "messageAction": null,
      "desiredDeliveryMediums": null
      }
    }
  </code></pre>
  
  <p>Then getting following response and user migrated into new pool means we have issue in trigger during login.</p>
  
  <pre><code> INFO   Authentication - response: {"userAttributes":{"email":"vaquar.test@gmail.com","email_verified":"true"},"forceAliasCreation":null,"finalUserStatus":"CONFIRMED","messageAction":"SUPPRESS","desiredDeliveryMediums":null}
  </code></pre>