'Change password using AWS.CognitoIdentityServiceProvider

I'm trying to figure out how to use the changePassword function of the AWS.CognitoIdentityServiceProvider.

I need to pass the following as params:

{
  PreviousPassword: 'STRING_VALUE', /* required */
  ProposedPassword: 'STRING_VALUE', /* required */
  AccessToken: 'STRING_VALUE'
}

I use this inside a Lambda function, so how do I get hold of the access token? I have the cognitoIdentityPoolId and the cognitoIdentityId to use, but I can't understand which this access token is.



Solution 1:[1]

Because there is no admin version of changePassword, you must first authenticate as the user you are trying to impact, then you can call the changePassword routine. It took me a long time to figure this out and no other posts seem to cover the case where you are running a NodeJS lambda function with the admin calls and UserPools, where you want to support "admin" changing of a user password. My (currently working) code is below. Note I believe preventing the admin from changing the user password is a deliberate design decision made by AWS, so I am not sure how long the workaround below will continue to be valid...

const cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider();


// Accept a POST with a JSON structure containing the
// refresh token provided during the original user login, 
// and an old and new password.
function changeUserPassword(event, context, callback) {
  // Extract relevant JSON into a request dict (This is my own utility code)
  let requiredFields = ['old_password','new_password','refresh_token'];
  let request = Utils.extractJSON(event['body'], requiredFields);
  if (request == false) {
    Utils.errorResponse("Invalid JSON or missing required fields", context.awsRequestId, callback);
    return; // Abort here
    }


  // This function can NOT be handled by admin APIs, so we need to
  // authenticate the user (not the admin) and use that
  // authentication instead.
  let refreshToken = request['refresh_token']

  // Authenticate as the user first, so we can call user version
  // of the ChangePassword API
  cognitoidentityserviceprovider.adminInitiateAuth({
    AuthFlow: 'REFRESH_TOKEN',
    ClientId: Config.ClientId,
    UserPoolId: Config.UserPoolId,
    AuthParameters: {
      'REFRESH_TOKEN': refreshToken
    },
    ContextData: getContextData(event)
  }, function(err, data) {
    if(err){
      Utils.errorResponse(err['message'], context.awsRequestId, callback);
      return // Abort here
    } else {
      // Now authenticated as user, change the password
      let accessToken = data['AuthenticationResult']['AccessToken'] // Returned from auth - diff signature than Authorization header
      let oldPass = request['old_password']
      let newPass = request['new_password']
      let params = {
        AccessToken: accessToken, /* required */
        PreviousPassword: oldPass, /* required */
        ProposedPassword: newPass /* required */
      }

      // At this point, really just a pass through
      cognitoidentityserviceprovider.changePassword(params, function(err2, data2) {
        if(err2){
          let message = {
            err_message: err2['message'],
            access_token: accessToken
          }
          Utils.errorResponse(message, context.awsRequestId, callback);
        } else {
          let response = {
            'success': 'OK',
            'response_data': data2 // Always seems to be empty
          }
          callback(response)
        }
      });
    }
  });

}

Solution 2:[2]

As You are using the AWS Lambda you dont need to worry about the access token you can simply pass the username and password along with the poolID to the cognito function adminSetUserPassword().this function will update the password easily

const updateCognitoPassword = async(user_name, password) => {
    try {
        var changePasswordParams = {
            Password: password,
            Permanent: true,
            Username: user_name.trim(),
            UserPoolId: constants.user_pool_id
        };
        let data = await cognitoidentityserviceprovider.adminSetUserPassword(changePasswordParams).promise();
        return data;
    }
    catch (err) {
        throw new Error(err);
    }
};

Solution 3:[3]

I would like to extend on some answers above with a solution that can be used inside the lambda function and also shows how to set the authentication required (using an AWS access key and secret access key.

This is a worked example of a "change password" function created as a lambda.

export async function  change_password (event, context, callback) {
  context.callbackWaitsForEmptyEventLoop = false;
  try {
    const { aws_cognito_id, newPassword } = JSON.parse(event.body)
    const cognitoIdentityService = new AWS.CognitoIdentityServiceProvider({ apiVersion: '2016-04-18', region: '***AWS REGION GOES HERE***' });
    const userPoolId = "***COGNITO USER POOL ID GOES HERE***";
    const params = {
        Password: newPassword,
        Permanent: true,
        Username: aws_cognito_id,
        UserPoolId: userPoolId
    };
    AWS.config.region = '**AWS REGION**';
    cognitoIdentityService.config.update({ 
       accessKeyId: '***AWS ACCESS KEY***', 
       secretAccessKey: '***AWS SECRET ACCESS KEY***' 
    })
    let result = await cognitoIdentityService.adminSetUserPassword(params).promise();
    return generate_response(200, result)
  } catch (err) {
    return generate_error(500, err.message)
  }
}

Solution 4:[4]

The identity pool id and identity id are Cognito federated identities concepts, while the ChangePassword API is a user pools one. They are two different services - think of user pools as an identity provider to your identity pool.

The short version is you can get the access token by signing in with a user in your user pool. Doing so returns an access token, id token, and refresh token. That being said, a common theme is to use the admin versions of the various user pool APIs on Lambda side, since you may not have user credentials there.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 John Robi
Solution 2
Solution 3 Andre DiCioccio
Solution 4 Jeff Bailey