I'm working on a login flow for my web app built in React and I'm using AWS Cognito for user management. I'm working on the login flow, and I have a use case where a user is created via the AWS Console and a temporary password is provided to the user. When the user goes to login to my application for the first time, AWS Cognito returns a newPasswordRequired Challenge, and the user is forced to change their password.
I'm using the amazon-cognito-identity-js
API to authenticate the user. The docs for that can be found here. I have the newPasswordRequired
callback function setup just like the docs instruct, but I'm struggling to figure out the best way to gather the new password from the user using React within the newPasswordRequired
function. I initially used prompt()
within the function to get the inputs, but I would like the app to flow to a new page where the user can enter a new password, confirm new password, and login to the app. That new page should be able to call the cognitoUser.completeNewPasswordChallenge()
that is required to update the new password. Please HELP! Here's my code below:
onFormSubmission = (username, password) => {
const poolData = {
UserPoolId : AWSConfig.cognito.USER_POOL_ID,
ClientId : AWSConfig.cognito.APP_CLIENT_ID
}
const userPool = new CognitoUserPool(poolData);
const userData = {
Username: username,
Pool: userPool
}
const authenticationData = {
Username : username,
Password : password
}
const authenticationDetails = new AuthenticationDetails(authenticationData);
const cognitoUser = new CognitoUser(userData);
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function (result) {
console.log('access token + ' + result.getAccessToken().getJwtToken());
/*Use the idToken for Logins Map when Federating User Pools with identity pools or when passing through an Authorization Header to an API Gateway Authorizer*/
console.log('idToken + ' + result.idToken.jwtToken);
},
onFailure: function(err) {
console.log(err);
},
newPasswordRequired: function(userAttributes, requiredAttributes) {
// User was signed up by an admin and must provide new
// password and required attributes, if any, to complete
// authentication.
// userAttributes: object, which is the user's current profile. It will list all attributes that are associated with the user.
// Required attributes according to schema, which don’t have any values yet, will have blank values.
// requiredAttributes: list of attributes that must be set by the user along with new password to complete the sign-in.
*** THIS IS WHERE I WANT REACT TO RENDER A NEW PAGE TO GET THE NEW PASSWORD***
// Get these details and call
// newPassword: password that user has given
// attributesData: object with key as attribute name and value that the user has given.
cognitoUser.completeNewPasswordChallenge(pw, userAttributes, this);
}
});
}
render() {
return (
<div>
<LoginScreenComponent isInvalidForm={this.state.isInvalidForm} onFormSubmission={this.onFormSubmission}/>
</div>
)
}
I had exactly the same problem! Here is my solution:
Login.js
react container can render two different components. <NewPassswordForm />
is to ask a new password, <LoginForm />
is for common login. According to isFirstLogin
flag you decide which one to render.
Since you have the cognito user in this.state.user
you can use it to call completeNewPasswordChallenge
to finish the login flow:
handleLogin = (username, password) => {
const authDetails = new AuthenticationDetails({
Username: username,
Password: password,
});
const userData = {
Username: username,
Pool: getUserPool(),
Storage: getStorage(),
};
const cognitoUser = new CognitoUser(userData);
cognitoUser.authenticateUser(authDetails, {
onSuccess: () => {
// login
}
newPasswordRequired: userAttr => {
this.setState({
isFirstLogin: true,
user: cognitoUser,
userAttr: userAttr,
});
},
});
};
changePassword = (newPassword) => {
const cognitoUser = this.state.user;
const userAttr = this.state.userAttr;
cognitoUser.completeNewPasswordChallenge(newPassword, userAttr, {
onSuccess: result => {
// login
}
});
};
render() {
return (
<div>
{this.state.isFirstLogin ? (
<NewPassswordForm changePassword={this.changePassword} />
) : (
<LoginForm handleLogin={this.handleLogin} />
)}
</div>
);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With