Describe the bug
When upgrading library to 1.1.10 login and logout seems to work, however changing password shows a Possible Unhandled Promise Rejection
To Reproduce
Steps to reproduce the behavior:
Auth.currentAuthenticatedUser()
.then((user) => {
return Auth.changePassword(user, oldPassword, newPassword)
})
.then((data) => {
console.log('changePassword:', data)
this.props.navigation.navigate('Profile')
})
.catch((err) => {
console.log(err)
})
Generates:
Possible Unhandled Promise Rejection (id: 0):
TypeError: user.getSession is not a function
TypeError: user.getSession is not a function
at blob:file:///6134849c-a9bf-4aff-8573-9a29532aed54:103866:22
at tryCallTwo (blob:file:///6134849c-a9bf-4aff-8573-9a29532aed54:8841:7)
at doResolve (blob:file:///6134849c-a9bf-4aff-8573-9a29532aed54:9005:15)
at new Promise (blob:file:///6134849c-a9bf-4aff-8573-9a29532aed54:8864:5)
at AuthClass.userSession (blob:file:///6134849c-a9bf-4aff-8573-9a29532aed54:103864:20)
at blob:file:///6134849c-a9bf-4aff-8573-9a29532aed54:103676:23
at tryCallTwo (blob:file:///6134849c-a9bf-4aff-8573-9a29532aed54:8841:7)
at doResolve (blob:file:///6134849c-a9bf-4aff-8573-9a29532aed54:9005:15)
at new Promise (blob:file:///6134849c-a9bf-4aff-8573-9a29532aed54:8864:5)
at AuthClass.userAttributes (blob:file:///6134849c-a9bf-4aff-8573-9a29532aed54:103675:20)
Expected behavior
I expect to change password per the documentation and not have any errors.
Smartphone (please complete the following information):
Additional context
@strykerCrew hi can you provide more info like the user you got from Auth.currentAuthenticatedUser(). You can also check the debug info by window.LOG_LEVEL='DEBUG'
[DEBUG] 16:40.65 AuthClass - Getting the session from this user:
:Object
aud: "..."
auth_time: 1543622644
cognito:username: "[email protected]"
email: "[email protected]"
email_verified: true
event_id: "..."
exp: 1543626244
iat: 1543622644
id: "..."
iss: "https://cognito-idp..."
sub: "..."
token_use: "id"
@strykerCrew That's weird. The user object should be a CognitoUser Object. Also I noticed that the tracing stack you pasted:
TypeError: user.getSession is not a function
at blob:file:///6134849c-a9bf-4aff-8573-9a29532aed54:103866:22
at tryCallTwo (blob:file:///6134849c-a9bf-4aff-8573-9a29532aed54:8841:7)
at doResolve (blob:file:///6134849c-a9bf-4aff-8573-9a29532aed54:9005:15)
at new Promise (blob:file:///6134849c-a9bf-4aff-8573-9a29532aed54:8864:5)
at AuthClass.userSession (blob:file:///6134849c-a9bf-4aff-8573-9a29532aed54:103864:20)
at blob:file:///6134849c-a9bf-4aff-8573-9a29532aed54:103676:23
at tryCallTwo (blob:file:///6134849c-a9bf-4aff-8573-9a29532aed54:8841:7)
at doResolve (blob:file:///6134849c-a9bf-4aff-8573-9a29532aed54:9005:15)
at new Promise (blob:file:///6134849c-a9bf-4aff-8573-9a29532aed54:8864:5)
at AuthClass.userAttributes (blob:file:///6134849c-a9bf-4aff-8573-9a29532aed54:103675:20)
Did you run userAttributes somewhere in your code? Or is it the full tracing stack? Maybe some other function is calling that. But as I know the currentAuthenticatedUser method doesn't call that function.
@powerful23 We don't have userAttributes anywhere in our code. This seems to be generated when the code hits return Auth.changePassword(user, oldPassword, newPassword) as the example code above.
This does work on aws-amplify=1.0.0, but breaks when we try to upgrade.
@powerful23 in the aws-amplify-react-native it uses Auth.completeNewPassword, should we be using that instead of Auth.changePassword?
We do not use aws-amplify-react-native and I didn't see the Auth.changePassword in the code for that package. Is it deprecated?
@strykerCrew we tried to reproduce your issue today but were unsuccessful. If you could would you be able to send us a gist or link to an example of your application code and the lifecycle of calling it in the app? Also, we have a Gitter channel https://gitter.im/AWS-Amplify/Lobby which our team could help you during the day tomorrow that might help for troubleshooting.
In the meantime, some thoughts: It could be that Auth.changePassword is being invoked out of band because the stack trace above shows AuthClass.userAttributes (blob:file:///6134849c-a9bf-4aff-8573-9a29532aed54:103675:20). Additionally, the user object you showed does not appear to be a valid Cognito user object.
We put together a sample below from scratch showing the API functionality as well as the user object that you should be seeing.
The below configuration file is automatically generated with the Amplify CLI when you run amplify add auth or you can manually create an Identity Pool and User Pool. Note that the aws_user_pools_web_client_id is an App client that does NOT have a client secret:
const awsmobile = {
'aws_cognito_identity_pool_id': 'us-east-1:xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx',
'aws_cognito_region': 'us-east-1',
'aws_sign_in_enabled': 'enable',
'aws_user_pools': 'enable',
'aws_user_pools_id': 'us-east-1_xxxxxxxxxxxxxxx',
'aws_user_pools_mfa_type': 'OFF',
'aws_user_pools_web_client_id': 'xxxxxxxxxxxxxxxxxxxxxxxx'
}
export default awsmobile;
The React Native application below was created with react-native init and demonstrates registering a user with a confirmation code, signing in with that user, and finally calling Auth.changePassword() in the application using the above configuration file. I hardcoded some variables such as the username, email, and passwords for demonstrative purposes:
import React, { Component } from 'react';
import { Platform, StyleSheet, Text, View, Button, Prompt, TextInput } from 'react-native';
import awsConfig from "./aws-exports";
import Amplify, { Auth } from "aws-amplify";
Amplify.configure(awsConfig);
const instructions = Platform.select({
ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu',
android:
'Double tap R on your keyboard to reload,\n' +
'Shake or press menu button for dev menu',
});
type Props = {};
export default class App extends Component<Props> {
constructor(props) {
super(props);
this.state = {
authState: 'signedOut',
user: null,
code: ''
}
}
handleSignIn = () => {
Auth.signIn('manuel', 'MyPassword123@').then(user => {
if (user.challengeName === 'SMS_MFA') {
// need to input code from sms
this.setState({ authState: 'verifyCode', user })
} else {
this.setState({ authState: 'signedIn' });
// logged in
}
}).catch(e => {
console.log(e);
});
}
verifyCode = () => {
Auth.confirmSignIn(this.state.user, this.state.code).then(data => {
console.log('success with: ' + data);
}).catch(err => {
console.log(err);
});
}
changePassword = () => {
const oldpassword = 'MyPassword123@';
const newpassword = 'NewPassword123@';
Auth.currentAuthenticatedUser().then(user => {
console.log(user);
Auth.changePassword(user, oldpassword, newpassword)
}).then(data => {
console.log('success with data: ' + data);
}).catch(e => {
console.log(e);
});
}
confirmSignUp = () => {
const username = 'manuel';
Auth.confirmSignUp(username, this.state.code).then(data => {
console.log('success with data: ', data);
}).catch(e => {
console.log(e);
});
}
handleSignUp = () => {
Auth.signUp({
username: 'manuel',
password: 'MyPassword123@',
attributes: {
email: '[email protected]',
phone_number: '+1234567890'
}
}).then(data => {
console.log('success with data: ', data);
}).catch(e => {
console.log(e);
});
}
render() {
const { authState } = this.state;
return (
<View style={styles.container}>
<Text style={styles.welcome}>Welcome to React Native!</Text>
<Text style={styles.instructions}>To get started, edit App.js</Text>
<Text style={styles.instructions}>{authState}</Text>
<Button title="Sign In" onPress={this.handleSignIn} />
<Button title="Sign Up" onPress={this.handleSignUp} />
<TextInput onChangeText={code => this.setState({ code })} />
<Button title="Confirm Sign Up" onPress={() => this.confirmSignUp()} />
{authState === 'signedIn' && <Button title="Change password" onPress={this.changePassword} />}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
Here is the package.json which is slightly different to your versions but the major version match:
{
"name": "happydonut",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest"
},
"dependencies": {
"aws-amplify": "1.1.10",
"react": "16.6.1",
"react-native": "0.57.7"
},
"devDependencies": {
"babel-jest": "23.6.0",
"jest": "23.6.0",
"metro-react-native-babel-preset": "0.50.0",
"react-test-renderer": "16.6.1"
},
"jest": {
"preset": "react-native"
When the above application code runs and you pass through the registration and sign-in flows, you will see a button that says "Change password" which upon clicking logs the user object. This is what I see when running this:
ReactNativeJS: { username: 'manuel',
ReactNativeJS: pool:
ReactNativeJS: { userPoolId: 'us-east-1_xxxxxxxxx',
ReactNativeJS: clientId: 'xxxxxxxxxxxxxx',
ReactNativeJS: client:
ReactNativeJS: { endpoint: 'https://cognito-idp.us-east-1.amazonaws.com/',
ReactNativeJS: userAgent: 'aws-amplify/0.1.x react-native' },
ReactNativeJS: advancedSecurityDataCollectionFlag: true,
ReactNativeJS: storage:
ReactNativeJS: { [Function: MemoryStorage]
ReactNativeJS: setItem: [Function],
ReactNativeJS: getItem: [Function],
ReactNativeJS: removeItem: [Function],
ReactNativeJS: clear: [Function],
ReactNativeJS: sync: [Function] } },
ReactNativeJS: Session: null,
ReactNativeJS: client:
ReactNativeJS: { endpoint: 'https://cognito-idp.us-east-1.amazonaws.com/',
ReactNativeJS: userAgent: 'aws-amplify/0.1.x react-native' },
ReactNativeJS: signInUserSession:
ReactNativeJS: { idToken:
ReactNativeJS: { jwtToken: 'xxxxxxxxxxxxxx',
ReactNativeJS: payload:
ReactNativeJS: { sub: 'xxxx-xxxx-xxxxx-xxx-xx',
ReactNativeJS: email_verified: false,
ReactNativeJS: iss: 'https://cognito-idp.us-east-1.amazonaws.com/us-east-1_xxxxxxxxxx',
ReactNativeJS: phone_number_verified: true,
ReactNativeJS: 'cognito:username': 'manuel',
ReactNativeJS: aud: 'xxxxxxxx',
ReactNativeJS: event_id: 'xxxxxx-xxxx-xxxx-xx-xxxxx',
ReactNativeJS: token_use: 'id',
ReactNativeJS: auth_time: 1543888416,
ReactNativeJS: phone_number: '+1234567890',
ReactNativeJS: exp: 1543892016,
ReactNativeJS: iat: 1543888416,
ReactNativeJS: email: '[email protected]' } },
Ok, so you are using new versions of react and react native than listed?
We are working on upgrading React to see if that fixes it.
@strykerCrew hi please notice that the sample code above only works when the MFA is not required in the Cognito User Pool(which means users can directly sign in).
Yes, I saw that. I am working on putting our code in a sample app to see if I still have the issue.
@manueliglesias thanks for the help, I was able to track it down by creating a new app with the latest React/React Native. It looks like the culprit comes from legacy code using the Auth.signIn followed by getting the user session followed by a Auth.federatedSignIn with Cognito. I simplified to Auth.signIn and then Auth.currentCredentials.
Why would this not break on auth and only show in the password change?
@strykerCrew We suspect that you might be calling federatedSignIn somewhere in your code and this is not needed in this case, because the library takes care of getting the credentials when you have an Identity Pool configured with a User Pool.
Could you confirm that's the case? If so, this would explain the problem; as roughly speaking, the federatedSignIn is an independent process which caches it's own user object which makes sense when running it independently. However if you use it along with the standard Auth methods that are already performing federation, problems occur.
If this is the case could you let us know why you might have thought that calling this separately in your code was necessary? We haven't seen customers do this before.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
This issue has been automatically closed because of inactivity. Please open a new issue if are still encountering problems.
Please find the below code . It worked for me.
async changePassword() {
var poolData = {
UserPoolId: "Your pool Id",
ClientId: "Your client Id"
};
var userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
var userData = {
Username: "current logged in username here",
Pool: userPool
};
var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
var authenticationData = {
Username: "current logged in username here",
Password: "current password"
};
var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails(authenticationData);
return cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function (session) {
if (session) {
return cognitoUser.changePassword("current password", "new password", async (err, result) => {
if (err) {
console.log("Change Password error is" + JSON.stringify(err) + err)
}
if (result) {
if (JSON.stringify(result) == "SUCCESS") {
Swal.fire({
title: "Success!",
text: "Your new password is updated successfully",
type: "success",
})
}
}
});
}
},
onFailure: function (err) {
console.log("authenticateUser() ERROR: " + err);
}
});
}
Most helpful comment
@strykerCrew we tried to reproduce your issue today but were unsuccessful. If you could would you be able to send us a gist or link to an example of your application code and the lifecycle of calling it in the app? Also, we have a Gitter channel https://gitter.im/AWS-Amplify/Lobby which our team could help you during the day tomorrow that might help for troubleshooting.
In the meantime, some thoughts: It could be that
Auth.changePasswordis being invoked out of band because the stack trace above showsAuthClass.userAttributes (blob:file:///6134849c-a9bf-4aff-8573-9a29532aed54:103675:20). Additionally, theuserobject you showed does not appear to be a valid Cognito user object.We put together a sample below from scratch showing the API functionality as well as the
userobject that you should be seeing.The below configuration file is automatically generated with the Amplify CLI when you run
amplify add author you can manually create an Identity Pool and User Pool. Note that theaws_user_pools_web_client_idis an App client that does NOT have a client secret:The React Native application below was created with
react-native initand demonstrates registering a user with a confirmation code, signing in with that user, and finally callingAuth.changePassword()in the application using the above configuration file. I hardcoded some variables such as the username, email, and passwords for demonstrative purposes:Here is the
package.jsonwhich is slightly different to your versions but the major version match:When the above application code runs and you pass through the registration and sign-in flows, you will see a button that says "Change password" which upon clicking logs the
userobject. This is what I see when running this: