Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

user.completeNewPasswordChallenge is not a function #1715

Closed
goatandsheep opened this issue Sep 21, 2018 · 22 comments
Closed

user.completeNewPasswordChallenge is not a function #1715

goatandsheep opened this issue Sep 21, 2018 · 22 comments
Labels
Auth Related to Auth components/category question General question

Comments

@goatandsheep
Copy link

Describe the bug
A clear and concise description of what the bug is.

To Reproduce
Steps to reproduce the behavior:

  1. Use flat aws-exports.js structure
  2. Set Cognito up such that Only Admin creates accounts
  3. Use Amplify but not mobile hub
  4. Create an account
  5. try to change the temporary password using Auth.completeNewPassword(userFromLoginAttempt, newPassword, requiredAttributes)
  6. Responds with user.completeNewPasswordChallenge is not a function

Expected behavior
Password is changed and the user can login

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: MacOS
  • Browser: Chrome
  • Version: 1.0.0

You can turn on the debug mode to provide more info for us by setting window.LOG_LEVEL = 'DEBUG'; in your app.

@powerful23 powerful23 added the Auth Related to Auth components/category label Sep 21, 2018
@powerful23
Copy link
Contributor

@goatandsheep hi can you confirm that the userFromLoginAttempt object should be a CognitoUser object?

@powerful23 powerful23 added the question General question label Sep 21, 2018
@goatandsheep
Copy link
Author

More details

upon Auth.signIn(), I receive a cognito user object. Unfortunately both Auth.currentSession() and Auth.currentAuthenticatedUser() came up as error instead of returning the user, so I couldn't access the CognitoUser object. As a workaround, I stored the user temporarily in localStorage. However, Amplify did not recognize the object after the JSON had been parsed. In addition, my router was auth-protected and clears the store when the above two functions return errors.

Fix

I whitelisted the password change page to not be auth protected and put the value into my store

Suggestion

Provide a way to obtain the user object when the user is not yet confirmed other than signIn. Even if it's located in the error message. I don't even know if it's cached.

@powerful23
Copy link
Contributor

@goatandsheep When you get resolved from Auth.signIn() with that user object, you are not actually signed in because you need to complete the new password. So at that moment Auth.currentSession and Auth.currentAuthenticatedUser won't work because you are not signed in. You need to directly use that user object returned from Auth.signIn() to help you finish the login process.

@goatandsheep
Copy link
Author

@powerful23 right! However, the user object that comes back from Auth.signIn() includes a session object, so it's inconsistent for Auth.currentSession() to not return the same session object. I would suggest you return it there if possible

@sankranti2018
Copy link

Same error..
e = TypeError: user.completeNewPasswordChallenge is not a function at eval (webpack:///./node_modules/@aws-amplify/auth/lib/Auth.js?:783:18) at new Promise () at AuthClass.completeNewPassword (webpack:///./node_modules/@aws-amplify/auth/lib/Auth.js?:782:16) at HTMLButtonElement.SubmitVerifyUserButton.addEventListener (webpack:///./src/app.js?:110:58)

CognitoUser {username: "fooUser", pool: CognitoUserPool, Session: "ysigtMhHzzzWchNgzYZnvfQg2cbWEjKFr6wR1lf1VA…Gl5Ua9XZphoX21tzCchHYxKzzdl_9hbihiQTzfHEy8_nrzs", client: Client, signInUserSession: null, …}

Code

aws_amplify__WEBPACK_IMPORTED_MODULE_0__["Auth"].signIn(userNameField.value, passwordField.value)
.then(user => {
console.log(user);
MessagesDiv.innerHTML = "Sign in success";
if(user.challengeName === "NEW_PASSWORD_REQUIRED"){
aws_amplify__WEBPACK_IMPORTED_MODULE_0__["Auth"].completeNewPassword(VerifyUser.value, 'NewPassword2018')
.then(() => {
MessagesDiv.innerHTML = "Sign in success. Password updated";
console.log('Password updated');

        })
        .catch(e => {
            MessagesDiv.innerHTML = "failed with error" + e;
            console.log('failed with error', e);
        });
    }

@goatandsheep
Copy link
Author

you're missing a lot in your workflow. Here let me help you out:

aws_amplify__WEBPACK_IMPORTED_MODULE_0__["Auth"].signIn(userNameField.value, passwordField.value)
  .then(user => {
    console.log(user);
    MessagesDiv.innerHTML = "Sign in success";
    if (user.challengeName === "SMS_MFA" || user.challengeName === "SOFTWARE_TOKEN_MFA") {
      aws_amplify__WEBPACK_IMPORTED_MODULE_0__["Auth"].confirmSignUp(/* TODO */)
    } else if(user.challengeName === "NEW_PASSWORD_REQUIRED"){
      aws_amplify__WEBPACK_IMPORTED_MODULE_0__["Auth"].completeNewPassword( VerifyUser.value, 'NewPassword2018')
        .then(() => {
          MessagesDiv.innerHTML = "Sign in success. Password updated";
          console.log('Password updated');
        })
        .catch(e => {
            MessagesDiv.innerHTML = "failed with error" + e;
            console.log('failed with error', e);
        });
    } else if (typeof user.challengeName !== 'undefined') {
      console.error(user.challengeName)
    }
    function checkUser(user) {
      aws_amplify__WEBPACK_IMPORTED_MODULE_0__["Auth"].verifiedContact(user)
        .then((data) => {
          console.log("verification result", data);
          if (Object.keys(data.verified).length > 0) {
            console.log("Successful login")
          } else {
            aws_amplify__WEBPACK_IMPORTED_MODULE_0__["Auth"].verifyContact(/* TODO */)
          }
        }
    }
    checkUser(user)

@sankranti2018
Copy link

Thank you for the help. I have few additional questions. 1. I am stepping through the code and see that the user.challengeName === "NEW_PASSWORD_REQUIRED" is true. The user status in cognito is FORCE_CHANGE_PASSWORD. So, the completeNewPassword is called but returns error *TypeError: user.completeNewPasswordChallenge is not a function at eval *. Although, the workflow steps you mention will have to be included in the production code, I have made MFA option turned off in the user pool configuration to keep things simple. I will try the code you have posted, turn MFA on and see if it resolves the error. I appreciate your help.

@goatandsheep
Copy link
Author

How are you calling Auth.completeNewPassword? Put the line here. It must have the following params:

  1. The user object directly from Auth.signIn
  2. The user's new password
  3. An object containing additional settings ( use {} if you don't have any)

@sankranti2018
Copy link

Thank you. Your response helped in identifying my mistake. The user object passed to Auth.completeNewPassword was different from the one returned by signin method so it was failing. After changing to use the object returned by signin it works correctly. Confirmed in cognito console that the status of user does change correctly.

@aussieweever
Copy link

aussieweever commented Oct 21, 2018

Anyone can confirm that the user object returned from signIn can be stored in the session storage via JSON.parse()?
When the user sign in at the first time, I redirect the page to the change password one, however when I use the stored user object to call the completeNewPassword() it always says the error as user.completeNewPasswordChallenge is not a function

@goatandsheep
Copy link
Author

goatandsheep commented Oct 21, 2018

I tried this (long story above - sessionstorage stores the same format as localstorage) and the object wasn't recognized properly. It needs to be a CognitoUser object. You're going to have to figure out how to pass it directly or put it in a 3rd party store like Redux or even Amplify Cache

@aussieweever
Copy link

Thanks mate. I finally use the BehaviourSubject to store the user (this project is based on Angular). In case the user refreshed the page then I'll take it as session expired and redirect the user to the login page. Not perfect, but should be able to satisfy the PO

@ziggahunhow
Copy link

this happened yesterday since we were using Immutable in redux reducers, which created a clone of the user object. If you are doing the same, please be aware and pass the user object directly.

@IsaacTrevino
Copy link

So this problem troubled me for some time. Amplify Cache didn't seem to work and caching username and password is a bad idea, however my work around was just include the username and password in the Require-New-Password form, so I have 4 inputs instead of just newPassword & confirmPassword which now is username, oldPassword, newPassword, and confirmPassword.

Good luck!

@nikhilknoldus
Copy link

You can simply use the predefined amplify method like below.
const currentUser = await Auth.currentAuthenticatedUser();

@mikeRChambers610
Copy link

const currentUser = await Auth.currentAuthenticatedUser();

how does this solve "TypeError: user.completeNewPasswordChallenge is not a function"??

@mikeRChambers610
Copy link

Thank you. Your response helped in identifying my mistake. The user object passed to Auth.completeNewPassword was different from the one returned by signin method so it was failing. After changing to use the object returned by signin it works correctly. Confirmed in cognito console that the status of user does change correctly.

Would you please provide the working example for the rest of us?

@davekiss
Copy link

@mikeRChambers610 you have to pass the object returned by Auth.signIn() instead of a username string. There isn't anything in the session yet, so @nikhilknoldus suggestion will not work

Here's an example using React: https://gist.github.com/davekiss/9af08fde4ce2d40e306a35028583d6e5

@yaayes
Copy link

yaayes commented Mar 16, 2021

I think it should be a method to create a CognitoUser instance from the returned object after stringify it and parse it again!

@mattjarzeb
Copy link

Here is some manual parsing to create CognitoUser instance from the parsed object (cognitoObject):

const pool = new CognitoUserPool({
      UserPoolId: cognitoObject.pool.userPoolId,
      ClientId: cognitoObject.pool.clientId,
      endpoint: cognitoObject.client.endpoint,
      Storage: window.localStorage,
      AdvancedSecurityDataCollectionFlag: cognitoObject.advancedSecurityDataCollectionFlag,
})
const cognitoUser = new CognitoUser({
      Username: cognitoObject.username,
      Pool: pool,
      Storage: window.localStorage,
})

cognitoUser.Session = cognitoObject.Session

await Auth.completeNewPassword(cognitoUser, newPassword, cognitoObject.challengeParams)

@successgilli
Copy link

successgilli commented Apr 29, 2021

More details

upon Auth.signIn(), I receive a cognito user object. Unfortunately both Auth.currentSession() and Auth.currentAuthenticatedUser() came up as error instead of returning the user, so I couldn't access the CognitoUser object. As a workaround, I stored the user temporarily in localStorage. However, Amplify did not recognize the object after the JSON had been parsed. In addition, my router was auth-protected and clears the store when the above two functions return errors.

Fix

I whitelisted the password change page to not be auth protected and put the value into my store

Suggestion

Provide a way to obtain the user object when the user is not yet confirmed other than signIn. Even if it's located in the error message. I don't even know if it's cached.

Anyone can confirm that the user object returned from signIn can be stored in the session storage via JSON.parse()?
When the user sign in at the first time, I redirect the page to the change password one, however when I use the stored user object to call the completeNewPassword() it always says the error as user.completeNewPasswordChallenge is not a function

yes, it would throw an error because the object is no longer a cognitoUserObject since it has been stringified and parsed.

What I did was to save the cognitoUserObject from sign-in to redux store and collect it back in the component where required.

@github-actions
Copy link

This issue has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs.

Looking for a help forum? We recommend joining the Amplify Community Discord server *-help channels or Discussions for those types of questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 30, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Auth Related to Auth components/category question General question
Projects
None yet
Development

No branches or pull requests