amplify-js: Auth.changePassword TypeError: user.getSession is not a function

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):

  • Device: iPhoneX Simulator

Additional context

  • “react”: “^16.3.1”,
  • “react-native”: “^0.55.4”,
  • “aws-amplify”: “^1.1.10”

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 6
  • Comments: 16 (5 by maintainers)

Most upvoted comments

@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@domain.com',
        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@domain.com' } },

@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.