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.42k stars 2.12k forks source link

Sessions aren't persisting between app reloads in React Native #4351

Closed CodySwannGT closed 4 years ago

CodySwannGT commented 4 years ago

Describe the bug Sessions aren't persisting between app reloads in Expo

To Reproduce Steps to reproduce the behavior:

  1. Open the app
  2. Sign in
  3. Reload the app
  4. See error

Expected behavior User still signed in

Sample code

import React, { useState, useEffect } from 'react';
import Amplify from 'aws-amplify';
import Auth from '@aws-amplify/auth'
import awsmobile from './aws-exports';
import { withAuthenticator } from 'aws-amplify-react-native';
import { Text } from 'react-native-elements';

const Test = () => console.log("OK OK OK HERE") || <Text>Hi</Text>

const TestWithAuth = withAuthenticator(Test)

Amplify.configure(awsmobile);

const App = () => {
  useEffect(() => {
    Auth.currentAuthenticatedUser()
      .then(cognitoUser => console.log(cognitoUser))
      .catch(err => console.log(err) || console.log(null))
  }, []);

  return (
    <TestWithAuth />
  );
}

export default App
ajdinahmetovic commented 4 years ago

@mickadoua Can you share package.json and how you use Auth.currentAuthenthicatedUser() ? Which version of react native are you using ?

mickadoua commented 4 years ago

@ajdinahmetovic hello and thanks for your help,

I use this code to get the CognitoToken

export async function getCognitoToken(): Promise<string> {
  const cognitoUser = await Auth.currentAuthenticatedUser();
  const currentSession = await Auth.currentSession();
  return await new Promise((resolve, reject) => {
    cognitoUser.refreshSession(
      currentSession.refreshToken,
      (err, session) => {
        if (err) {
          reject(err);
        }
        return resolve(session.idToken.jwtToken);
      },
    );
  });
}
Environment ``` System: OS: macOS 10.15.2 CPU: (12) x64 Intel(R) Core(TM) i7-8850H CPU @ 2.60GHz Memory: 76.56 MB / 16.00 GB Shell: 5.7.1 - /bin/zsh Binaries: Node: 12.7.0 - ~/.nvm/versions/node/v12.7.0/bin/node Yarn: 1.21.1 - ~/code/client/psa/react-native/node_modules/.bin/yarn npm: 6.10.0 - ~/.nvm/versions/node/v12.7.0/bin/npm Browsers: Chrome: 79.0.3945.88 Safari: 13.0.4 npmPackages: @babel/core: 7.6.2 => 7.6.2 @babel/preset-flow: 7.0.0 => 7.0.0 @babel/register: ^7.6.2 => 7.7.4 @babel/runtime: 7.5.5 => 7.5.5 @bam.tech/react-native-batch: 5.0.2 => 5.0.2 @mapbox/polyline: 1.0.0 => 1.0.0 @react-native-community/async-storage: ^1.7.1 => 1.7.1 @react-native-community/eslint-config: ^0.0.5 => 0.0.5 @react-native-community/geolocation: ^2.0.2 => 2.0.2 @react-native-community/google-signin: ^3.0.3 => 3.0.3 @react-native-community/netinfo: 4.6.1 => 4.6.1 @react-native-community/slider: 2.0.7 => 2.0.7 @react-native-firebase/analytics: ^6.1.0 => 6.2.0 @react-native-firebase/app: ^6.1.0 => 6.2.0 @react-native-firebase/crashlytics: ^6.1.0 => 6.2.0 @react-native-firebase/perf: ^6.1.0 => 6.2.0 add: ^2.0.6 => 2.0.6 amazon-cognito-identity-js: ^3.2.0 => 3.2.0 aws-amplify: ^2.2.0 => 2.2.0 axios: ^0.19.0 => 0.19.0 babel-eslint: 10.0.1 => 10.0.1 babel-jest: 24.9.0 => 24.9.0 babel-plugin-module-resolver: ^3.2.0 => 3.2.0 babel-plugin-transform-inline-environment-variables: 0.4.3 => 0.4.3 babel-plugin-transform-object-rest-spread: 6.26.0 => 6.26.0 babel-plugin-transform-remove-console: 6.9.4 => 6.9.4 babel-runtime: 6.26.0 => 6.26.0 base64-arraybuffer: 0.2.0 => 0.2.0 enzyme: 3.9.0 => 3.9.0 enzyme-adapter-react-16: 1.12.1 => 1.12.1 eslint: 6.5.1 => 6.5.1 eslint-config-airbnb-standard: 3.0.1 => 3.0.1 eslint-config-prettier: 4.1.0 => 4.1.0 eslint-import-resolver-alias: ^1.1.2 => 1.1.2 eslint-plugin-flowtype: 4.2.0 => 4.2.0 eslint-plugin-import: ^2.18.0 => 2.19.1 eslint-plugin-prettier: 3.0.1 => 3.0.1 eslint-plugin-react: 7.12.4 => 7.12.4 eslint-plugin-react-native: 3.6.0 => 3.6.0 eslint-plugin-react-native-a11y: 1.2.0 => 1.2.0 fetch: 1.1.0 => 1.1.0 filequeue: ^0.5.0 => 0.5.0 flow-bin: 0.105.1 => 0.105.1 flow-typed: 2.6.1 => 2.6.1 flowgen: ^1.10.0 => 1.10.0 google-polyline: 1.0.3 => 1.0.3 hoist-non-react-statics: 3.3.0 => 3.3.0 husky: 1.3.1 => 1.3.1 i18n-js: ^3.3.0 => 3.5.0 intl: 1.2.5 => 1.2.5 jest: 24.9.0 => 24.9.0 jest-enzyme: 7.0.2 => 7.0.2 jest-react-native: 18.0.0 => 18.0.0 jest-sonar-reporter: 2.0.0 => 2.0.0 jetifier: ^1.6.4 => 1.6.5 jwt-decode: ^2.2.0 => 2.2.0 libphonenumber-js: 0.4.31 => 0.4.31 lint-staged: 8.1.5 => 8.1.5 lodash: 4.17.11 => 4.17.11 metro-react-native-babel-preset: 0.56.0 => 0.56.0 moment: 2.24.0 => 2.24.0 moment-duration-format: ^2.3.2 => 2.3.2 moment-timezone: 0.5.26 => 0.5.26 prettier: 1.17.0 => 1.17.0 prettier-eslint: 8.8.2 => 8.8.2 prop-types: 15.7.2 => 15.7.2 react: 16.9.0 => 16.9.0 react-dom: 16.8.6 => 16.8.6 react-intl-native: 2.1.2 => 2.1.2 react-native: 0.61.5 => 0.61.5 react-native-adjust: 4.18.2 => 4.18.2 react-native-animatable: 1.3.3 => 1.3.3 react-native-device-info: 5.3.1 => 5.3.1 react-native-dotenv: 0.2.0 => 0.2.0 react-native-fbsdk: 1.1.1 => 1.1.1 react-native-fs: 2.16.2 => 2.16.2 react-native-geolocation-service: 3.1.0 => 3.1.0 react-native-gesture-handler: 1.5.2 => 1.5.2 react-native-google-maps: 1.0.0 => 1.0.0 react-native-htmlview: 0.14.0 => 0.14.0 react-native-keyboard-accessory: 0.1.10 => 0.1.10 react-native-keyboard-aware-scroll-view: 0.9.1 => 0.9.1 react-native-linear-gradient: 2.5.6 => 2.5.6 react-native-localize: ^1.3.1 => 1.3.1 react-native-mail: 4.1.0 => 4.1.0 react-native-map-link: 2.5.2 => 2.5.2 react-native-maps: 0.26.1 => 0.26.1 react-native-page-control: 1.1.1 => 1.1.1 react-native-permissions: ^2.0.4 => 2.0.8 react-native-reanimated: ^1.4.0 => 1.4.0 react-native-screens: 2.0.0-alpha.13 => 2.0.0-alpha.13 react-native-splash-screen: 3.2.0 => 3.2.0 react-native-svg: 9.13.3 => 9.13.3 react-native-swiper: ^1.6.0-rc.3 => 1.6.0-rc.3 react-native-webview: 7.5.2 => 7.5.2 react-navigation: 4.0.10 => 4.0.10 react-navigation-animated-switch: ^0.3.2 => 0.3.2 react-navigation-drawer: ^2.3.3 => 2.3.3 react-navigation-hooks: 1.1.0 => 1.1.0 react-navigation-stack: ^1.10.3 => 1.10.3 react-redux: 7.1.3 => 7.1.3 redux: 4.0.4 => 4.0.4 redux-logger: 3.0.6 => 3.0.6 redux-mock-store: 1.5.3 => 1.5.3 redux-persist: 6.0.0 => 6.0.0 redux-saga: 0.16.0 => 0.16.0 redux-thunk: 2.3.0 => 2.3.0 rxjs: 6.4.0 => 6.4.0 sonar-scanner: 3.1.0 => 3.1.0 source-map: ^0.7.3 => 0.7.3 uuid-js: 0.7.5 => 0.7.5 yarn: ^1.19.2 => 1.21.1 npmGlobalPackages: @nestjs/cli: 6.6.3 bit-bin: 14.4.3 expo-cli: 3.4.1 gatsby-cli: 2.8.19 npm: 6.10.0 ```
ajdinahmetovic commented 4 years ago

@mickadoua Thank you I will try to use this to fix issue tommorow and reach out if I have any further problems.

claudioviola commented 4 years ago

@mickadoua @ajdinahmetovic Yours scenario seems very similar to mine. The very weird aspect of this issue is that it shows suddenly out. Read my post above: I didn't change any dependencies from my project but suddenly the currentAuthenticatedUser stopped working. https://github.com/aws-amplify/amplify-js/issues/4351#issuecomment-566555291

How can it happens? I mean without updating dependencies how is it possible it suddenly stopped working? 🤔

Shaninnik commented 4 years ago

I am having the same issue. It was working fine for month and then stopped working after minor version update. Rolling back to version I was using before or updating to latest have not worked. In my case I am doing federatedSignIn it works fine and calling currentAuthenticatedUser({ bypassCache: true }) right after signIn returns user data. However after app reload calling currentAuthenticatedUser({ bypassCache: true }) returns Not authenticated error. Doing just currentAuthenticatedUser() works

KristineTrona commented 4 years ago

I am having the issue now as well. It seemed fixed before, but the same as with @claudioviola it is not working anymore even though I did not update aws-amplify

Neovirxp commented 4 years ago

I'm still having this issue. Sometimes it works well, but just a few times. It's really weird and frustrating. Update: @anthonyhumphreys solution works yet! So, the issue sholud be reopened!

KristineTrona commented 4 years ago

@Ashish-Nanda This issue should indeed be reopened:

My package.json:

    "amazon-cognito-identity-js": "^3.2.0",
    "aws-amplify": "^2.1.0",

I have also tried using "aws-amplify" 2.2.0 and this did not fix the issue. Also tried calling Auth.currentAuthenticatedUser({ bypassCache: true }) - also does not fix the issue.

Closing the app and reopening it sometimes does and sometimes does not remove the Cognito user session.

If I go to node_modules/@aws-amplify/core/src/RNComponents/reactnative.ts i see that it is still using the old AsyncStorage:

Screenshot 2020-01-23 at 15 52 45

Same in node_modules/@aws-amplify/core/src/StorageHelper/reactnative.ts:

Screenshot 2020-01-23 at 15 53 45

And package.json in node_modules/@aws-amplify/core/package.json says version: "2.2.1" If I upgrade to aws-amplify version 2.2.0 I see the same Async Storage import from react-native core.

Ashish-Nanda commented 4 years ago

@KristineTrona what version of react native are you using? The issue was not related to not using the community edition of AsyncStorage, since it is still part of react native (atleast till 0.61.5) and there are some more details in this comment

Please give some more details about your project, and maybe some sample code so we can try to repro the issue you are having. Regarding the user credentials not being persisted, does it only happen when you kill the app? How consistently does it happen? Please give a few repro steps to ensure we can try it the same way.

KristineTrona commented 4 years ago

@Ashish-Nanda Thanks for the reply - I am using RN 0.61.4, no expo. In my project I am initially rendering a launch screen and checking whether there is a current authenticated cognito user and based on that route the user to either home screen or login screen respectively.

In LaunchScreen.js:

  async componentDidMount() {
    const { navigation } = this.props;

    try {
      await Auth.currentAuthenticatedUser();
      navigation.navigate('HomeScreen');
    } catch (e) {
      navigation.navigate(‘LoginScreen');
    }
}

Sometimes re-opening the app does not cause any problems, but sometimes it does. It is very random. I had created a build and reopened the app 10 times to test it and 10/10 times did not encounter the problem. Then suddenly it started to happen again. I have a feeling it fails mostly on an actual device with a release build, and not on the simulator. I am also only testing using iOS, and the app is being built for an iPad, not iPhone.

Also as a temporary fix I implemented the fix suggested by @anthonyhumphreys and that seems to be working without any issues so far, which makes me really believe that something could be wrong with the AsyncStorage. Hope this helps to reproduce the issue.

ranjeev75 commented 4 years ago

I'm getting a similar error, where after authentication I can get files from my S3 bucket. the logs reflect this:

[DEBUG] 00:39.767 Credentials - getting credentials ConsoleLogger.js:76 [DEBUG] 00:39.768 Credentials - picking up credentials ConsoleLogger.js:76 [DEBUG] 00:39.769 Credentials - getting new cred promise ConsoleLogger.js:76 [DEBUG] 00:39.769 Credentials - checking if credentials exists and not expired ConsoleLogger.js:76 [DEBUG] 00:39.771 Credentials - credentials not changed and not expired, directly return ConsoleLogger.js:83 [DEBUG] 00:39.773 AWSS3Provider - set credentials for storage {accessKeyId: "xxx", sessionToken: "xxx", secretAccessKey: "xxx", identityId: "xxxx", authenticated: true}

But on app reload these credentials are not persisted:

[DEBUG] 06:34.92 Credentials - getting credentials ConsoleLogger.js:76 [DEBUG] 06:34.93 Credentials - picking up credentials ConsoleLogger.js:76 [DEBUG] 06:34.94 Credentials - getting new cred promise ConsoleLogger.js:76 [DEBUG] 06:34.95 Credentials - checking if credentials exists and not expired ConsoleLogger.js:76 [DEBUG] 06:34.96 Credentials - need to get a new credential or refresh the existing one ConsoleLogger.js:76 [DEBUG] 06:34.98 AuthClass - Getting current user credentials ConsoleLogger.js:76 [DEBUG] 06:34.101 Credentials - Getting federated credentials ConsoleLogger.js:76 [DEBUG] 06:34.101 Credentials - checking if federated jwt token expired ConsoleLogger.js:83 [DEBUG] 06:34.102 Credentials - no refresh handler for provider: xxx.auth0.com ConsoleLogger.js:76 [DEBUG] 06:34.104 AsyncStorageCache - Remove item: key is federatedInfo backend.js:32 [WARN] 06:34.106 AWSS3Provider - ensure credentials error no refresh handler for provider69 Bio.tsx:51 No credentials

Dependencies are:

    "@react-native-community/async-storage": "^1.9.0",
    "aws-amplify": "2.2.2",
    "aws-amplify-react-native": "^4.0.4",
    "react-native": "0.62.2",

How can I persist/ fetch credentials on app reload to stop this occuring?

proevilz commented 4 years ago

I'm using the following and have this exact issue... when reloading, login is not persisted. There are so many comments/workarounds on here but I'm unsure which one I'm supposed to do, or if it's supposed to be working/patched now considering this issue is closed?

"aws-amplify": "^3.0.16",
"expo": "~37.0.9",
"react-native": "https://github.com/expo/react-native/archive/sdk-37.0.1.tar.gz",
fuhreeus commented 4 years ago

I'm getting this same error without expo...still "aws-amplify": "^3.0.11", "aws-amplify-react": "^4.1.10", "bootstrap": "^4.5.0", "formik": "^2.1.4", "react": "^16.13.1",

nihp commented 4 years ago

Here I am not using storage in config.

I need to reload the app after logout to navigate the login screen

jvsteiner commented 3 years ago

@Ashish-Nanda why is this issue closed? It seems that many users are still having this problem, and there is an active and continuing stream of posts about this. I would also point out that this is not only a react problem - I am having the exact same behavior in my vue application.

jmkmay commented 3 years ago

We are also having this issue. Quite frustrated having chosen Amplify due to it being touted as an out-of-the-box solution. Our experience has been anything but...

Shaninnik commented 3 years ago

This issue is definitely not resolved. We had all workarounds implemented (including custom MemoryStorage that uses non-deprecated AsyncStorage import) but still had issues with users being logged out await Auth.currentAuthenticatedUser(); was still randomly throwing and logs confirmed that. Worst of all there was absolutely no pattern for that and we could not replicate that in controlled environment. Our experience with Amplify was a nightmare. In the end we've decided that it is easier for us to switch to different auth service.

jmkmay commented 3 years ago

@Shaninnik unfortunately we're stuck with it for AWS integration...

I've spent the last day and a half or so trying different approaches to solving this issue: implementing custom storage class, using refreshHandlers... to no avail. Its frustrating because user login via Cognito IdP (email, password) works just fine and doens't experience this issue.

yagiraldo62 commented 3 years ago

I am having the same issue, I tried with a custom storage class, and I realized that although the currentAuthenticatedUser function returns undefined, when the storage´s getItem function is called, the session values are returned by AsyncStorage, for some reason the currentAuthenticatedUser function cannot access to those values. if we print in console the requested values inside storage class´s sync and getItem functions, session values are returned

Captura image

majirosstefan commented 2 years ago

Well, I also think this should not be closed at all.

I am using RN "0.65.1", "amazon-cognito-identity-js": "^5.2.0", "aws-amplify": "^4.3.1", "aws-amplify-react-native": "^5.0.3", "@react-native-async-storage/async-storage": "^1.15.9", iOS 15.0, and iPhone 12 simulator running on non-M1 mac.

When I did not configure storage manually using "workaround" above like this:

Amplify.configure({
  ...config,
  Auth: {
    storage: MemoryStorageNew,
  },
});

I was still 'logged out' / not signed in upon reloading or reopening the app. So, could you reopen this issue, please?

I also think it would be nice to update docs https://docs.amplify.aws/lib/auth/manageusers/q/platform/js/#managing-security-tokens, as you are still using "import { AsyncStorage } from 'react-native;" in some parts.

CodySwannGT commented 2 years ago

Amazing - over two years old, and we still have to use the MemoryStorageNew patch

zzBrunoBrito commented 2 years ago

Facing the same issue here currently...

Vordy commented 2 years ago

It's kinda scary tbh

jmkmay commented 2 years ago

We ended up fixing this issue.

Make sure you have Implicit Grant enabled in in your App Client.

The Auth Flow configuration that got it working for us is as follows:

image

This turned out to be a configuration issue for us, I assume that might by why it was closed.

Goszu commented 2 years ago

I am using "@aws-amplify/auth": "4.3.20" and the settings are same as above. I can confirm this is still an issue. I am on expo managed flow using expo-secure-store for storage. When I roll back to "@aws-amplify/auth": "2.1.8" everything works as expected.

abury commented 2 years ago

I'm also seeing this. Non Expo project.

    "react": "17.0.2",
    "react-native": "0.66.3",
    "amazon-cognito-identity-js": "^5.2.7",
    "aws-amplify": "^4.3.15",
    "aws-amplify-react-native": "^6.0.3",

The other thing I noticed is that calling SignIn seems to cause the UI Thread to hang on 9/10 calls, which seems a bit strange. Not sure if it's related though.

Update After a fair bit of research, I've opted out of using Amplify and to use Cognito directly and handle session management myself. Not ideal, but also not terrible either. amazon-cognito-identity-js is simple and does the job well.

relaxedcoder commented 2 years ago

I was facing the same issue of user not persisting after app restart in amazon-cognito-identity-js, and after a lot of searching I stumbled upon the following part of the README:

Use case 16 with React Native In React Native, loading the persisted current user information requires an extra async call to be made:

userPool.storage.sync(function(err, result) {
if (err) {
} else if (result === 'SUCCESS') {
var cognitoUser = userPool.getCurrentUser();
// Continue with steps in Use case 16
}
});

This means that at app startup(usually inside App.js), you have to call this function to transfer the items from the async storage to the memory storage for it to detect the current user.

"react": "17.0.2",
"react-native": "0.68.2",
"amazon-cognito-identity-js": "^5.2.9",
"expo": "~45.0.0",
"@react-native-async-storage/async-storage": "~1.17.3",

I'm sorry if I am pointing to something obvious, but it may help someone who may have skipped over this part.

github-actions[bot] commented 1 year 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 amplify-help forum.