4

I've been following the Serverless Stack tutorial and can get a positive response with calling Auth.signIn(username, passsword)

The current workflow we have is that the user will need to reset their password as accounts will be handed out.

The .changePassword function takes 3 arguments; user, oldPassword, newPassword

I can't for the life of me figure out what it's looking for for the user. When I set the object returned from .signIn() I get the following error:

Local storage is missing an ID Token, Please authenticate

Obviously I wouldn't use this flow for production, but I'm trying to figure out what Auth is looking for.

Auth.signIn(this.state.emailAddress, this.state.password)
  .then(user => {
    this.setState({ isLoading: false, user });
  }).then(async () => {
    Auth.changePassword(this.state.user, 'P@ssw0rd!', 'NewP@ssw0rd!');
  }).catch(err => {
    this.setState({ isLoading: false, errorMessage: err.message })
});

I do see an ID token in the Storage property from the object returned from .signIn. For clarification: I probably shouldn't have placed it in the chaining. I'm not really doing above in practice. When I save the response from Signin and pass it to the changePassword I get the localstorage error. I'm wondering if there is a config issue setting up Amplify that normally would place this info in localStorage.

Blue
  • 22,608
  • 7
  • 62
  • 92
Jon Harding
  • 4,928
  • 13
  • 51
  • 96

1 Answers1

1

Auth.changePassword takes in a CognitoUser as it's first argument, something which should be returned from Auth.signIn.

The issue here, is your promise chaining, and using this.setState() and reading it back before it's actually been set:

Auth.signIn(this.state.emailAddress, this.state.password)
  .then(user => {
    // Triggers a setstate here:
    this.setState({ isLoading: false, user });
  }).then(async () => {
    // this.state.user is not defined at this point
    Auth.changePassword(this.state.user, 'P@ssw0rd!', 'NewP@ssw0rd!');
  }).catch(err => {
    this.setState({ isLoading: false, errorMessage: err.message })
});

From the React docs:

setState() does not always immediately update the component. It may batch or defer the update until later. This makes reading this.state right after calling setState() a potential pitfall. Instead, use componentDidUpdate or a setState callback (setState(updater, callback)), either of which are guaranteed to fire after the update has been applied. If you need to set the state based on the previous state, read about the updater argument below.

The easiest way to fix this, is to return the user in the first .then callback, to pass it to the second:

Auth.signIn(this.state.emailAddress, this.state.password)
  .then(user => {
    // Triggers a setstate here:
    this.setState({ isLoading: false, user });
    return user;
  }).then((user) => {
    // this.state.user is not defined at this point
    Auth.changePassword(user, 'P@ssw0rd!', 'NewP@ssw0rd!');
  }).catch(err => {
    this.setState({ isLoading: false, errorMessage: err.message })
});

Personally, I think it would look a lot nicer entirely in async/await:

try {
    const user = await Auth.signIn(this.state.emailAddress, this.state.password);

    this.setState({ isLoading: false, user });

    await Auth.changePassword(user, 'P@ssw0rd!', 'NewP@ssw0rd!');
} catch (err) {
    this.setState({ isLoading: false, errorMessage: err.message })
}
Blue
  • 22,608
  • 7
  • 62
  • 92
  • I probably shouldn't have placed it in the chaining. I'm not really doing that in practice. When I save the response from Signin and pass it to the changePassword I get the localstorage error. I completely agree it should be what is returned from Signin, that's why I'm confused. I'm wondering if there is a config issue setting up Amplify that normally would place this info in localStorage – Jon Harding Dec 03 '18 at 19:11
  • Looking at [this issue](https://github.com/aws-amplify/amplify-js/issues/1853) @JonHarding, could it be "You guys need to use the `completeNewPassword` method instead of `changePassword`. This will actually complete the auth challenge presented by the API."? – Blue Dec 06 '18 at 02:24
  • I haven't been able to revisit this for a while. Did you get the bounty points? – Jon Harding Dec 07 '18 at 19:21
  • Nope, expired this morning with no winning bounty @JonHarding – Blue Dec 07 '18 at 20:56