aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.43k stars 2.13k forks source link

AWS-Amplify + React Native: Keep user logged in, even after they exit/close the app #8703

Closed surabhigupta2029 closed 3 years ago

surabhigupta2029 commented 3 years ago

Before opening, please confirm:

JavaScript Framework

React Native

Amplify APIs

Authentication, GraphQL API, Storage

Amplify Categories

auth

Environment information

React native: 0.63.2 AWS-Amplify Expo

Describe the bug

Problem: When the user exits the app, and goes to another app for instance or goes back to phone home screen, and THEN reopen my app, the user has to re log in. I want to make sure the user's log in session stays alive forever (if its possible) or atleast for a couple of days.

Technologies: react native, iOS, Expo (for testing purposes)

Expected behavior

Currently, our app has sign in, sign out, and sign up functionality using AWS Amplify's built in methods. Sign out is only triggered when the user goes into the settings page and explicitly clicks "log out" button.

Reproduction steps

We can't provide repository due to confidentiality reasons, but this is the general flow:

  1. Register for app
  2. Log out
  3. Log in
  4. Exit app (as in switch to another app, or keep it open in background)
  5. Re-open app --> asks user to log in again to access their account

Code Snippet

This is code only relating to the relevant functionalities, and these work successfully without any issues.

//-------------SIGN UP -----------------

userSignIn = async () => { await Auth.signIn(this.state.email, this.state.password) // If successful -> General user registration .then((res) => { this.props.navigation.navigate('Registration2') console.log("user signed in"); })

        // Error
        .catch(err => console.log(err));
}

handleConfirmationCode = async () => {
    const { email, confirmationCode } = this.state;
    await Auth.confirmSignUp(email, confirmationCode, {})
        .then(async () => {
            this.setState({ modalVisible: false });
            this.setState({ disabled: true });
            await this.userSignIn();
        })
        .catch(
            err => alert(err.message)
        );
};

//-------------SIGN IN -----------------

getAnswerFunct = async () => { await Auth.currentAuthenticatedUser({ bypassCache: false // Optional, By default is false. If set to true, this call will send a request to Cognito to get the latest user data }) .then(async (user) => { this.setState({ email: user.attributes.email }); const userEmail = this.state.email; console.log('email', userEmail) await API.graphql(graphqlOperation(getAnswer, { id: userEmail })) .then(answers => { console.log("in then 2 ", answers) const cur_obj = answers.data.getAnswer; console.log('bio', cur_obj) if (cur_obj == null) { this.props.navigation.navigate('Registration2'); } else { this.props.navigation.navigate('BottomNavigator'); } }) .catch(err => console.log(err)); }) .catch(err => console.log(err)); } handleSignIn = async () => { const { email, password } = this.state; this.setState({ disabled: true }); await Auth.signIn(email, password) // If we are successful, navigate to Home screen .then(() => { console.log("then handlesignin") this.getAnswerFunct(); }) // On failure, display error in console .catch(err => { this.setState({ disabled: false }); alert("Incorrect username and/or password.") }); }

// ---------------------- SIGN OUT ----------------------- logOutPressed = async () => { await Auth.signOut() .then(console.log("successful log out")) .catch(err => console.log(err)); this.props.navigation.navigate("FeatureList"); };

Log output

``` // Put your logs below this line ```

aws-exports.js

No response

Manual configuration

No response

Additional configuration

No response

Mobile Device

No response

Mobile Operating System

No response

Mobile Browser

No response

Mobile Browser Version

No response

Additional information and screenshots

No response

chrisbonifacio commented 3 years ago

Hello @surabhigupta2029 been trying to reproduce this issue. I'm curious to know if you are experiencing this on the iOS simulator, physical device, or both?

surabhigupta2029 commented 3 years ago

Hello @surabhigupta2029 been trying to reproduce this issue. I'm curious to know if you are experiencing this on the iOS simulator, physical device, or both?

Hello, this is happening on the simulator. We are using Expo as the simulator app on our phones.

surabhigupta2029 commented 3 years ago

Moreover, as a side note, there is no code in here for the functionality we are trying to code.

chrisbonifacio commented 3 years ago

Okay, thank you! I am also using the simulator to reproduce. Would you be able to paste the dependencies of your project within the package.json file here? I really just need any related to amplify and the versions. It would also be to check if you have @react-native-async-storage installed as well.

surabhigupta2029 commented 3 years ago

This is our package.json:

{ "main": "node_modules/expo/AppEntry.js", "scripts": { "start": "expo start", "android": "expo start --android", "ios": "expo start --ios", "web": "expo start --web", "eject": "expo eject" }, "dependencies": { "@aws-sdk/client-cognito-identity-provider": "^3.21.0", "@expo-google-fonts/montserrat": "^0.1.0", "@expo-google-fonts/nunito": "^0.1.0", "@expo-google-fonts/playfair-display": "^0.1.0", "@expo-google-fonts/yeseva-one": "^0.1.0", "@react-native-async-storage/async-storage": "^1.13.0", "@react-native-community/masked-view": "0.1.10", "@react-native-community/netinfo": "^6.0.0", "@react-native-picker/picker": "1.9.11", "@react-navigation/material-bottom-tabs": "^5.3.15", "@react-navigation/material-top-tabs": "^5.3.15", "@react-navigation/native": "^5.9.4", "@react-navigation/stack": "^5.14.5", "aws-amplify": "4.2.0", "aws-amplify-react-native": "5.0.3", "crypto-js": "^4.0.0", "expo": "^41.0.0", "expo-app-loading": "^1.0.3", "expo-blur": "~9.0.3", "expo-font": "~9.1.0", "expo-status-bar": "~1.0.4", "graphql": "^14.0.0", "moment": "^2.29.1", "react": "16.13.1", "react-dom": "16.13.1", "react-native": "https://github.com/expo/react-native/archive/sdk-41.0.0.tar.gz", "react-native-animated-scroll-indicators": "^1.0.1", "react-native-deck-swiper": "^2.0.5", "react-native-elements": "^3.3.2", "react-native-gesture-handler": "^1.8.0", "react-native-hide-show-password-input": "^1.2.0", "react-native-hyperlink": "0.0.19", "react-native-image-picker": "^4.0.4", "react-native-keyboard-aware-scroll-view": "^0.9.4", "react-native-keyboard-listener": "^1.1.0", "react-native-modal": "^11.10.0", "react-native-modal-selector": "^2.0.6", "react-native-multiple-select": "^0.5.6", "react-native-paper": "^4.9.1", "react-native-picker-select": "^8.0.4", "react-native-progress": "^4.1.2", "react-native-reanimated": "~2.1.0", "react-native-safe-area-context": "3.2.0", "react-native-screens": "~3.0.0", "react-native-snap-carousel": "^3.9.1", "react-native-use-keyboard-height": "^0.1.1", "react-native-vector-icons": "^8.1.0", "react-native-web": "~0.13.12", "typescript": "^4.3.5", "uuidv4": "^6.2.11" }, "devDependencies": { "@babel/core": "^7.14.6" }, "resolutions": { "amazon-cognito-identity-js": "^4.5.1" }, "private": true }

chrisbonifacio commented 3 years ago

Thank you!

Unfortunately I have not been able to reproduce this issue so far. Can you add this code to the App.js file of your application to check your AsyncStorage when the app comes back to the foreground? I'm just curious to see if the credentials are no longer there when returning to the app.

  // add this to your 'react-native' import
  import { AppState } from "react-native";

  const appState = React.useRef(AppState.currentState);

  // this will create a map of the values in your AsyncStorage
  const checkAsyncStorage = async () => {
    let storage = {};

    try {
      const keys = await AsyncStorage.getAllKeys();

      for (let key of keys) {
        const value = await AsyncStorage.getItem(key);
        storage[key] = value;
      }
    } catch (error) {
      console.error(error);
    }

    Object.keys(storage).length
      ? console.table(storage)
      : console.log("Storage is empty");
  };

  // this will listen for the changes in your app state and log AsyncStorage when the app comes to the foreground
  const _handleAppStateChange = async (nextAppState) => {
    if (
      appState.current.match(/inactive|background/) &&
      nextAppState === "active"
    ) {
      console.log("App has come to the foreground!");
      await checkAsyncStorage();
    }

    appState.current = nextAppState;
    console.log("AppState", appState.current);
  };

  // this will setup the listener to trigger when the AppState changes
  React.useEffect(() => {
    AppState.addEventListener("change", _handleAppStateChange);

    return () => {
      AppState.removeEventListener("change", _handleAppStateChange);
    };
  }, []);

If you are using the React Native Debugger you should be able to see a table like this one with the credentials or, if storage is empty just a message stating that.

Screen Shot 2021-08-05 at 2 20 53 PM

If storage is empty when app comes to foreground

Screen Shot 2021-08-05 at 2 23 35 PM
chrisbonifacio commented 3 years ago

Hey @surabhigupta2029. I realized the internal support ticket related to this issue was resolved so I'm going to close this issue accordingly. Thank you for reaching out and answering my questions on this issue! Please still feel free to let us know if you are still in need of assistance and we can re-open 😃 .

github-actions[bot] commented 2 years ago

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.