How to change User Status FORCE_CHANGE_PASSWORD?
Asked Answered
A

14

215

Using AWS Cognito, I want to create dummy users for testing purposes.

I then use the AWS Console to create such user, but the user has its status set to FORCE_CHANGE_PASSWORD. With that value, this user cannot be authenticated.

Is there a way to change this status?

UPDATE Same behavior when creating user from CLI

Airing answered 27/10, 2016 at 14:17 Comment(1)
User answer provided by @joeTarttan
H
322

This has finally been added to AWSCLI: https://docs.aws.amazon.com/cli/latest/reference/cognito-idp/admin-set-user-password.html

You can change a user's password and update status using:

aws cognito-idp admin-set-user-password \
  --user-pool-id <your-user-pool-id> \
  --username <username> \
  --password <password> \
  --permanent

Before using this, you may need to update your AWS CLI using:

pip3 install awscli --upgrade

Hence answered 9/7, 2019 at 8:19 Comment(9)
This is the latest and most efficient solution!Tarttan
Note that Permanent must be set to True; Otherwise the user will still be in the FORCE_CHANGE_PASSWORD state.Stringy
the command lacks a "\" at the end of line 1: Must be `aws cognito-idp admin-set-user-password \`Bignoniaceous
This is a manual step. You can do this directly in code: https://mcmap.net/q/125604/-how-to-change-user-status-force_change_passwordStreeto
It can only be done after the user is created. Can't we set a permanent password while creating a user?Spartan
I get "ResourceNotFoundException: User pool does not exist.". Does anyone knows why aws CLI cannot see my user pool ?Gainless
To avoid confusing errors when using the AWS CLI with Cognito, it's important to include the --region flag with the appropriate region value for your Cognito user pool.Barroom
It's work for me , Thank you. I can change the confirmation status from FORCE_CHANGE_PASSWORD to CONFIRMED. AppreciatedUndistinguished
how do you send the invitation mail again?Batish
P
166

I know it's been a while but thought this might help other people who come across this post.

You can use the AWS CLI to change the users password, however it's a multi step process:


Step 1: Get a session token for the desired user:

aws cognito-idp admin-initiate-auth --user-pool-id %USER POOL ID% --client-id %APP CLIENT ID% --auth-flow ADMIN_NO_SRP_AUTH --auth-parameters USERNAME=%USERS USERNAME%,PASSWORD=%USERS CURRENT PASSWORD%

If this returns an error about Unable to verify secret hash for client, create another app client without a secret and use that client ID.

Step 2: If step 1 is successful, it will respond with the challenge NEW_PASSWORD_REQUIRED, other challenge parameters and the users session key. Then, you can run the second command to issue the challenge response:

aws cognito-idp admin-respond-to-auth-challenge --user-pool-id %USER POOL ID% --client-id %CLIENT ID% --challenge-name NEW_PASSWORD_REQUIRED --challenge-responses NEW_PASSWORD=%DESIRED PASSWORD%,USERNAME=%USERS USERNAME% --session %SESSION KEY FROM PREVIOUS COMMAND with ""%

If you get an error about Invalid attributes given, XXX is missing pass the missing attributes using the format userAttributes.$FIELD_NAME=$VALUE

The above command should return a valid Authentication Result and appropriate Tokens.


Important: For this to work, the Cognito User Pool MUST have an App client configured with ADMIN_NO_SRP_AUTH functionality (Step 5 in this doc).

Paschall answered 22/7, 2017 at 9:37 Comment(4)
Amazingly helpful. Two more tips: if you get an error about "Unable to verify secret hash for client", create another app client without a secret and use that (#37439379). If you get an error about "Invalid attributes given, XXX is missing," pass the missing attributes using the format userAttributes.$FIELD_NAME=$VALUE (github.com/aws/aws-sdk-js/issues/1290).Eunaeunice
If you can't get your user out of FORCE_CHANGE_PASSWORD, with any of the CLI commands, (including this answer) try 'admin-disable-user' then 'admin-enable-user' or use the console. Then either user this process, or you might be able to use normal password reset flow. Sometime a user will 'expire' if the didn't log into cognito within the predefined limit. (default 7 days I think)Laylalayman
Tried it with CLI and inside a lambda, got this error: Invalid attributes given, name is missingHugohugon
@misher you're getting that due to required attributes. you can include them in the call but the syntax is a bit weird: --challenge-responses NEW_PASSWORD=password,USERNAME=username,userAttributes.picture=picture,userAttributes.name=nameCharlton
N
27

You can change that user status FORCE_CHANGE_PASSWORD by calling respondToAuthChallenge() on the user like this:

var params = {
  ChallengeName: 'NEW_PASSWORD_REQUIRED', 
  ClientId: 'your_own3j6...0obh',
  ChallengeResponses: {
    USERNAME: 'user3',
    NEW_PASSWORD: 'changed12345'
  },
  Session: 'xxxxxxxxxxZDMcRu-5u...sCvrmZb6tHY'
};

cognitoidentityserviceprovider.respondToAuthChallenge(params, function(err, data) {
  if (err) console.log(err, err.stack); // an error occurred
  else     console.log(data);           // successful response
});

After this, you'll see in the console that user3 status is CONFIRMED.

Northeast answered 13/11, 2016 at 2:22 Comment(8)
I don't understand how you got here. What did you call to get the Session that you've XXX'd out? When I call adminInitiateAuth I get an error saying UserNotFoundException.Pesce
Sorry if that answer wasn't crystal clear. Here are more details: 1. The User Pool has a client called 'your_own3j63rs8j16bxxxsto25db00obh' which is created WITHOUT a generated secret key. The above code will not work if the client is assigned a key. 2) Session key is the value returned by calling cognitoidentityserviceprovider.adminInitiateAuth({ AuthFlow: 'ADMIN_NO_SRP_AUTH', ClientId: 'your_own3j63rs8j16bxxxsto25db00obh', UserPoolId: 'us-east-1_DtNSUVT7n', AuthParameters: { USERNAME: 'user3', PASSWORD: 'original_password' } }, callback);Northeast
3) user3 was created in the console and initially given the password 'original_password'Northeast
OK. I get now why I was getting a UserNotFoundException. It was because I was using an alias as the username to login, which works fine in the JS API but apparently doesn't work with adminInitiateAuth. Thank you Ariel Araza, I appreciate your help.Pesce
Yay! I finally got this to work. Thank you! Thank you Ariel!Pesce
Glad to be of help Ryan!Northeast
got an error: Invalid attributes given, name is missingHugohugon
C# people follow the same parameters as mention above.Hairy
S
27

Just add this code after your onSuccess: function (result) { ... }, within your login function. Your user will then have status CONFIRMED.

newPasswordRequired: function(userAttributes, requiredAttributes) {
    // User was signed up by an admin and must provide new
    // password and required attributes, if any, to complete
    // authentication.

    // the api doesn't accept this field back
    delete userAttributes.email_verified;

    // unsure about this field, but I don't send this back
    delete userAttributes.phone_number_verified;

    // Get these details and call
    cognitoUser.completeNewPasswordChallenge(newPassword, userAttributes, this);
}
Streeto answered 29/9, 2017 at 9:12 Comment(2)
This works for me. You can even pass in the current password if you don't want to change it.Brutal
Recursion FTW! thanks! (recursion is the this on the complete new password challenge)Divers
I
19

Sorry you are having difficulties. We do not have a one step process where you can just create users and authenticate them directly. We might change this in the future such as to allow administrators to set passwords that are directly usable by users. For now, when you create users either using AdminCreateUser or by signing up users with the app, extra steps are required, either forcing users to change the password upon login or having users verify the email or phone number to change the status of the user to CONFIRMED.

Isolative answered 31/10, 2016 at 22:54 Comment(2)
For now, when you create users either using AdminCreateUser or by signing up users with the app, extra steps are required, either forcing users to change the password upon login or having users verify the email or phone number to change the status of the user to CONFIRMED. What exactly are these extra efoorts and how can I trigger them from JS SDK.Eichmann
@joe pointed out that it is now possible, since it was added. look for the --permanent flag: https://mcmap.net/q/125604/-how-to-change-user-status-force_change_passwordMusic
S
15

not sure if you are still fighting with this but for creating a bunch of test users only, I used the awscli as such:

  1. Use the sign-up subcommand from cognito-idp to create the user
aws cognito-idp sign-up \
   --region %aws_project_region% \
   --client-id %aws_user_pools_web_client_id% \
   --username %email_address% \
   --password %password% \
   --user-attributes Name=email,Value=%email_address%
  1. Confirm the user using admin-confirm-sign-up
aws cognito-idp admin-confirm-sign-up \
--user-pool-id %aws_user_pools_web_client_id% \
--username %email_address%
Sotos answered 29/1, 2019 at 7:46 Comment(0)
S
10

UPDATE:

There have been some updates, and Amplify client is no longer needed. After adminCreateUser(), you can now just use

cisp.adminSetUserPassword({
  UserPoolId: pool_id,
  Username: login,
  Password: password,
  Permanent: true
}) 

[https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminSetUserPassword.html]

this will set the user to "confirmed".

UPDATE:

I am now using this, translated to amplify, inside a NodeJS Lambda:

// enable node-fetch polyfill for Node.js
global.fetch = require("node-fetch").default;
global.navigator = {};

const AWS = require("aws-sdk");
const cisp = new AWS.CognitoIdentityServiceProvider();

const Amplify = require("@aws-amplify/core").default;
const Auth = require("@aws-amplify/auth").default;

...


/*
  this_user: {
    given_name: string,
    password: string,
    email: string,
    cell: string
  }
*/
const create_cognito = (this_user) => {
  let this_defaults = {
    password_temp: Math.random().toString(36).slice(-8),
    password: this_user.password,
    region: global._env === "prod" ? production_region : development_region,
    UserPoolId:
      global._env === "prod"
        ? production_user_pool
        : development_user_pool,
    ClientId:
      global._env === "prod"
        ? production_client_id
        : development_client_id,
    given_name: this_user.given_name,
    email: this_user.email,
    cell: this_user.cell,
  };

  // configure Amplify
  Amplify.configure({
    Auth: {
      region: this_defaults.region,
      userPoolId: this_defaults.UserPoolId,
      userPoolWebClientId: this_defaults.ClientId,
    },
  });
  if (!Auth.configure())
    return Promise.reject("could not configure amplify");

  return new Promise((resolve, reject) => {
    let _result = {};

    let this_account = undefined;
    let this_account_details = undefined;

    // create cognito account
    cisp
      .adminCreateUser({
        UserPoolId: this_defaults.UserPoolId,
        Username: this_defaults.given_name,
        DesiredDeliveryMediums: ["EMAIL"],
        ForceAliasCreation: false,
        MessageAction: "SUPPRESS",
        TemporaryPassword: this_defaults.password_temp,
        UserAttributes: [
          { Name: "given_name", Value: this_defaults.given_name },
          { Name: "email", Value: this_defaults.email },
          { Name: "phone_number", Value: this_defaults.cell },
          { Name: "email_verified", Value: "true" },
        ],
      })
      .promise()
      .then((user) => {
        console.warn(".. create_cognito: create..");
        _result.username = user.User.Username;
        _result.temporaryPassword = this_defaults.password_temp;
        _result.password = this_defaults.password;

        // sign into cognito account
        return Auth.signIn(_result.username, _result.temporaryPassword);
      })
      .then((user) => {
        console.warn(".. create_cognito: signin..");

        // complete challenge
        return Auth.completeNewPassword(user, _result.password, {
          email: this_defaults.email,
          phone_number: this_defaults.cell,
        });
      })
      .then((user) => {
        console.warn(".. create_cognito: confirmed..");
        this_account = user;
        // get details
        return Auth.currentAuthenticatedUser();
      })
      .then((this_details) => {
        if (!(this_details && this_details.attributes))
          throw "account creation failes";

        this_account_details = Object.assign({}, this_details.attributes);

        // signout
        return this_account.signOut();
      })
      .then(() => {
        console.warn(".. create_cognito: complete");
        resolve(this_account_details);
      })
      .catch((err) => {
        console.error(".. create_cognito: error");
        console.error(err);
        reject(err);
      });
  });
};

I am setting a temp password and then later resetting it to the user's requested password.

OLD POST:

You can solve this using the amazon-cognito-identity-js SDK by authenticating with the temporary password after the account creation with cognitoidentityserviceprovider.adminCreateUser(), and running cognitoUser.completeNewPasswordChallenge() within cognitoUser.authenticateUser( ,{newPasswordRequired}) - all inside the function that creates your user.

I am using the below code inside AWS lambda to create enabled Cognito user accounts. I am sure it can be optimized, be patient with me. This is my first post, and I am still pretty new to JavaScript.

var AWS = require("aws-sdk");
var AWSCognito = require("amazon-cognito-identity-js");

var params = {
    UserPoolId: your_poolId,
    Username: your_username,
    DesiredDeliveryMediums: ["EMAIL"],
    ForceAliasCreation: false,
    MessageAction: "SUPPRESS",
    TemporaryPassword: your_temporaryPassword,
    UserAttributes: [
        { Name: "given_name", Value: your_given_name },
        { Name: "email", Value: your_email },
        { Name: "phone_number", Value: your_phone_number },
        { Name: "email_verified", Value: "true" }
    ]
};

var cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider();
let promise = new Promise((resolve, reject) => {
    cognitoidentityserviceprovider.adminCreateUser(params, function(err, data) {
        if (err) {
            reject(err);
        } else {
            resolve(data);
        }
    });
});

promise
    .then(data => {
        // login as new user and completeNewPasswordChallenge
        var anotherPromise = new Promise((resolve, reject) => {
            var authenticationDetails = new AWSCognito.AuthenticationDetails({
                Username: your_username,
                Password: your_temporaryPassword
            });
            var poolData = {
                UserPoolId: your_poolId,
                ClientId: your_clientId
            };
            var userPool = new AWSCognito.CognitoUserPool(poolData);
            var userData = {
                Username: your_username,
                Pool: userPool
            };

            var cognitoUser = new AWSCognito.CognitoUser(userData);
            let finalPromise = new Promise((resolve, reject) => {
                cognitoUser.authenticateUser(authenticationDetails, {
                    onSuccess: function(authResult) {
                        cognitoUser.getSession(function(err) {
                            if (err) {
                            } else {
                                cognitoUser.getUserAttributes(function(
                                    err,
                                    attResult
                                ) {
                                    if (err) {
                                    } else {
                                        resolve(authResult);
                                    }
                                });
                            }
                        });
                    },
                    onFailure: function(err) {
                        reject(err);
                    },
                    newPasswordRequired(userAttributes, []) {
                        delete userAttributes.email_verified;
                        cognitoUser.completeNewPasswordChallenge(
                            your_newPoassword,
                            userAttributes,
                            this
                        );
                    }
                });
            });

            finalPromise
                .then(finalResult => {
                    // signout
                    cognitoUser.signOut();
                    // further action, e.g. email to new user
                    resolve(finalResult);
                })
                .catch(err => {
                    reject(err);
                });
        });
        return anotherPromise;
    })
    .then(() => {
        resolve(finalResult);
    })
    .catch(err => {
        reject({ statusCode: 406, error: err });
    });
Stambaugh answered 18/12, 2017 at 16:40 Comment(4)
@Tom - does it work for you? anything I can clarify?Stambaugh
Much better now.Dedicated
@Stambaugh use promises and callbacks at the same time? Why?Housebroken
@Iurii Golskyi - back then I didn't know better, had just started learning both AWS and JS from scratch.Stambaugh
C
7

If you are trying to change status as a admin from the console. Then follow the below steps after creating the user.

  1. In Cognito goto -> "manage user pool" ->
  2. Goto "App client settings" under App integration section.
  3. Check on the below items i) Cognito User Pool ii) Authorization code grant iii) Implicit grant iv) phone v) email vi) openid vii) aws.cognito.signin.user.admin viii) profile
  4. Enter the callback url of your application. If you are not sure enter for example: https://google.com and later you can change it to your actual callback url
  5. click on save changes.
  6. Once changes are saved click on the link "Launch Hosted UI"
  7. Enter the credentials of the new created user
  8. Reset the password with new credentials and share the same to the user

step 2

step 3 4 5 6

step 7

step 8

Conspiracy answered 29/1, 2020 at 4:57 Comment(1)
This did it for me. Couldn't update pw through aws command as thats been depreciated. AWS was not a known command in my setup.Anonymous
B
6

For Java SDK, assuming your Cognito client is setup and you have your user in the FORCE_CHANGE_PASSWORD state you can do the following to get your user CONFIRMED... and then auth'd as normal.

AdminCreateUserResult createUserResult = COGNITO_CLIENT.adminCreateUser(createUserRequest());

AdminInitiateAuthResult authResult = COGNITO_CLIENT.adminInitiateAuth(authUserRequest());


Map<String,String> challengeResponses = new HashMap<>();
challengeResponses.put("USERNAME", USERNAME);
challengeResponses.put("NEW_PASSWORD", PASSWORD);
RespondToAuthChallengeRequest respondToAuthChallengeRequest = new RespondToAuthChallengeRequest()
      .withChallengeName("NEW_PASSWORD_REQUIRED")
      .withClientId(CLIENT_ID)
      .withChallengeResponses(challengeResponses)
      .withSession(authResult.getSession());

COGNITO_CLIENT.respondToAuthChallenge(respondToAuthChallengeRequest);

Hope it helps with those integration tests (Sorry about the formatting)

Bulldozer answered 30/4, 2018 at 21:28 Comment(0)
E
6

Basically this is the same answer but for .Net C# SDK:

The following will make a full admin user creation with desired username and password. Having the following User model:

public class User
{
    public string Username { get; set; }
    public string Password { get; set; }
}

You can create a user and make it ready to use using:

   public void AddUser(User user)
    {
        var tempPassword = "ANY";
        var request = new AdminCreateUserRequest()
        {
            Username = user.Username,
            UserPoolId = "MyuserPoolId",
            TemporaryPassword = tempPassword
        };
        var result = _cognitoClient.AdminCreateUserAsync(request).Result;
        var authResponse = _cognitoClient.AdminInitiateAuthAsync(new AdminInitiateAuthRequest()
        {
            UserPoolId = "MyuserPoolId",
            ClientId = "MyClientId",
            AuthFlow = AuthFlowType.ADMIN_NO_SRP_AUTH,
            AuthParameters = new Dictionary<string, string>()
            {
                {"USERNAME",user.Username },
                {"PASSWORD", tempPassword}
            }
        }).Result;
        _cognitoClient.RespondToAuthChallengeAsync(new RespondToAuthChallengeRequest()
        {
         ClientId = "MyClientId",
            ChallengeName = ChallengeNameType.NEW_PASSWORD_REQUIRED,
            ChallengeResponses = new Dictionary<string, string>()
            {
                {"USERNAME",user.Username },
                {"NEW_PASSWORD",user.Password }
            },
            Session = authResponse.Session
        });
    }
Eat answered 16/2, 2019 at 13:3 Comment(0)
P
3

OK. I finally have code where an administrator can create a new user. The process goes like this:

  1. Admin creates the user
  2. User receives an email with their temporary password
  3. User logs in and is asked to change their password

Step 1 is the hard part. Here's my code for creating a user in Node JS:

let params = {
  UserPoolId: "@cognito_pool_id@",
  Username: username,
  DesiredDeliveryMediums: ["EMAIL"],
  ForceAliasCreation: false,
  UserAttributes: [
    { Name: "given_name", Value: firstName },
    { Name: "family_name", Value: lastName},
    { Name: "name", Value: firstName + " " + lastName},
    { Name: "email", Value: email},
    { Name: "custom:title", Value: title},
    { Name: "custom:company", Value: company + ""}
  ],
};
let cognitoIdentityServiceProvider = new AWS.CognitoIdentityServiceProvider();
cognitoIdentityServiceProvider.adminCreateUser(params, function(error, data) {
  if (error) {
    console.log("Error adding user to cognito: " + error, error.stack);
    reject(error);
  } else {
    // Uncomment for interesting but verbose logging...
    //console.log("Received back from cognito: " + CommonUtils.stringify(data));
    cognitoIdentityServiceProvider.adminUpdateUserAttributes({
      UserAttributes: [{
        Name: "email_verified",
        Value: "true"
      }],
      UserPoolId: "@cognito_pool_id@",
      Username: username
    }, function(err) {
      if (err) {
        console.log(err, err.stack);
      } else {
        console.log("Success!");
        resolve(data);
      }
    });
  }
});

Basically, you need to send a second command to force the email to be considered verified. The user still needs to go to their email to get the temporary password (which also verifies the email). But without that second call that sets the email to verified, you won't get the right call back to reset their password.

Pesce answered 28/7, 2017 at 22:2 Comment(3)
I still don't receive the e-mail, any suggestion?Knurl
Weird, Have you set up the email address correctly in Cognito, with access to SES, etc? Cogntio won't just send emails to people until you've either verified the email address you're trying to send to or you get approved to send to anybody.Pesce
I receive confirmation code e-mails, so the settings are correct. Just the e-mail with the temporary password never comes... I ended up creating a lambda attached to the pre-signup trigger to send the e-mail.Knurl
P
3

I know It is the same answer, but thought it might help Go developer community. basically it is initiating auth request, get the session and respond to the challenge NEW_PASSWORD_REQUIRED

func sessionWithDefaultRegion(region string) *session.Session {
    sess := Session.Copy()
    if v := aws.StringValue(sess.Config.Region); len(v) == 0 {
        sess.Config.Region = aws.String(region)
    }

    return sess
}



func (c *CognitoAppClient) ChangePassword(userName, currentPassword, newPassword string)   error {

    sess := sessionWithDefaultRegion(c.Region)
    svc := cognitoidentityprovider.New(sess)

    auth, err := svc.AdminInitiateAuth(&cognitoidentityprovider.AdminInitiateAuthInput{
        UserPoolId:aws.String(c.UserPoolID),
        ClientId:aws.String(c.ClientID),
        AuthFlow:aws.String("ADMIN_NO_SRP_AUTH"),
        AuthParameters: map[string]*string{
            "USERNAME": aws.String(userName),
            "PASSWORD": aws.String(currentPassword),
        },

    })



    if err != nil {
        return err
    }

    request := &cognitoidentityprovider.AdminRespondToAuthChallengeInput{
        ChallengeName: aws.String("NEW_PASSWORD_REQUIRED"),
        ClientId:aws.String(c.ClientID),
        UserPoolId: aws.String(c.UserPoolID),
        ChallengeResponses:map[string]*string{
            "USERNAME":aws.String(userName),
            "NEW_PASSWORD": aws.String(newPassword),
        },
        Session:auth.Session,
    }


    _, err = svc.AdminRespondToAuthChallenge(request)

    return err 
}

Here's a unit test:

import (
    "fmt"
    "github.com/aws/aws-sdk-go/service/cognitoidentityprovider"
    . "github.com/smartystreets/goconvey/convey"
    "testing"
)


func TestCognitoAppClient_ChangePassword(t *testing.T) {


    Convey("Testing ChangePassword!", t, func() {
        err := client.ChangePassword("user_name_here", "current_pass", "new_pass")



        Convey("Testing ChangePassword Results!", func() {
            So(err, ShouldBeNil)

        })

    })
}
Puga answered 3/4, 2019 at 3:2 Comment(0)
B
1

I have been many times in the same situation. So wrote small CLI in golang to exactly either auth as user ( for further testing purposes ) or just administratively reset the pass.

Then all what you run as command is

$ > go-cognito-authy --profile cloudy -region eu-central-1 admin reset-pass --username rafpe --pass-new 'Password.0ne2!' --clientID 2jxxxiuui123 --userPoolID  eu-central-1_CWNnTiR0j --session "bCqSkLeoJR_ys...."

Solution is available on github https://github.com/RafPe/go-cognito-authy/tree/master

Basketry answered 22/1, 2021 at 16:23 Comment(0)
M
0

You can also just use the Hosted UI of Cognito in case you have one for your application. Just login with the desired user and you will be prompted to change your password. After that the users status is confirmed and you can proceed as normal.

Mamiemamma answered 31/8, 2022 at 17:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.