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

DataStore.query Returns Null for User Data After Re-Auth and Clear in React Native #13060

Closed Glognus closed 6 months ago

Glognus commented 8 months ago

Before opening, please confirm:

JavaScript Framework

React Native

Amplify APIs

Authentication, DataStore

Amplify Version

v6

Amplify Categories

auth, api

Backend

Amplify CLI

Environment information

``` System: OS: macOS 14.3.1 CPU: (8) arm64 Apple M2 Memory: 738.28 MB / 16.00 GB Shell: 5.9 - /bin/zsh Binaries: Node: 21.5.0 - ~/.nvm/versions/node/v21.5.0/bin/node Yarn: 4.0.2 - ~/.nvm/versions/node/v21.5.0/bin/yarn npm: 10.2.4 - ~/.nvm/versions/node/v21.5.0/bin/npm Browsers: Chrome: 122.0.6261.69 Safari: 17.3.1 npmPackages: @aws-amplify/datastore-storage-adapter: ^2.1.17 => 2.1.17 @aws-amplify/predictions: ^6.0.17 => 6.0.17 @aws-amplify/react-native: ^1.0.17 => 1.0.17 @aws-amplify/rtn-web-browser: ^1.0.17 => 1.0.17 @aws-amplify/ui-react-native: ^2.1.2 => 2.1.2 @babel/core: ^7.23.9 => 7.23.9 (7.23.7) @babel/plugin-proposal-export-namespace-from: ^7.18.9 => 7.18.9 @babel/plugin-proposal-nullish-coalescing-operator: ^7.18.6 => 7.18.6 @babel/plugin-proposal-optional-chaining: ^7.21.0 => 7.21.0 @expo/vector-icons: ^13.0.0 => 13.0.0 (14.0.0) @faker-js/faker: ^8.4.1 => 8.4.1 @gorhom/bottom-sheet: ^4.6.1 => 4.6.1 @react-native-async-storage/async-storage: 1.22.2 => 1.22.2 @react-native-community/netinfo: 11.3.0 => 11.3.0 @react-native-masked-view/masked-view: 0.3.1 => 0.3.1 @react-native-picker/picker: 2.6.1 => 2.6.1 @react-navigation/bottom-tabs: ^6.5.14 => 6.5.14 (6.5.11) @react-navigation/native: ^6.1.12 => 6.1.12 (6.1.9) @shopify/flash-list: 1.6.3 => 1.6.3 @shopify/restyle: ^2.4.2 => 2.4.2 @types/base-64: ^1.0.2 => 1.0.2 @types/react: ~18.2.59 => 18.2.59 @types/react-native-base64: ^0.2.2 => 0.2.2 @typescript-eslint/eslint-plugin: ^7.1.0 => 7.1.0 @typescript-eslint/parser: ^7.1.0 => 7.1.0 HelloWorld: 0.0.1 aws-amplify: ^6.0.17 => 6.0.17 aws-amplify/adapter-core: undefined () aws-amplify/analytics: undefined () aws-amplify/analytics/kinesis: undefined () aws-amplify/analytics/kinesis-firehose: undefined () aws-amplify/analytics/personalize: undefined () aws-amplify/analytics/pinpoint: undefined () aws-amplify/api: undefined () aws-amplify/api/server: undefined () aws-amplify/auth: undefined () aws-amplify/auth/cognito: undefined () aws-amplify/auth/cognito/server: undefined () aws-amplify/auth/enable-oauth-listener: undefined () aws-amplify/auth/server: undefined () aws-amplify/datastore: undefined () aws-amplify/in-app-messaging: undefined () aws-amplify/in-app-messaging/pinpoint: undefined () aws-amplify/push-notifications: undefined () aws-amplify/push-notifications/pinpoint: undefined () aws-amplify/storage: undefined () aws-amplify/storage/s3: undefined () aws-amplify/storage/s3/server: undefined () aws-amplify/storage/server: undefined () aws-amplify/utils: undefined () axios: ^1.6.7 => 1.6.7 babel-plugin-inline-import: ^3.0.0 => 3.0.0 base-64: ^1.0.0 => 1.0.0 core-js: ^3.36.0 => 3.36.0 (2.6.12, 1.2.7) eas-cli: ~7.1.3 => 7.1.3 eslint: ~8.57.0 => 8.57.0 expo: ~50.0.7 => 50.0.7 expo-av: ~13.10.5 => 13.10.5 expo-blur: ~12.9.2 => 12.9.2 expo-build-properties: ~0.11.1 => 0.11.1 expo-constants: ~15.4.5 => 15.4.5 (15.4.3) expo-crypto: ~12.8.1 => 12.8.1 expo-dev-client: ~3.3.8 => 3.3.8 expo-file-system: ~16.0.6 => 16.0.6 (16.0.3) expo-font: ~11.10.3 => 11.10.3 expo-image: ~1.10.6 => 1.10.6 expo-image-manipulator: ~11.8.0 => 11.8.0 expo-image-picker: ~14.7.1 => 14.7.1 expo-insights: ~0.6.1 => 0.6.1 expo-linear-gradient: ~12.7.2 => 12.7.2 expo-linking: ~6.2.2 => 6.2.2 expo-location: ~16.5.3 => 16.5.3 expo-permissions: ~14.4.0 => 14.4.0 expo-router: ~3.4.7 => 3.4.7 expo-splash-screen: ~0.26.4 => 0.26.4 expo-status-bar: ~1.11.1 => 1.11.1 expo-system-ui: ~2.9.3 => 2.9.3 expo-updates: ~0.24.11 => 0.24.11 expo-web-browser: ~12.8.2 => 12.8.2 lottie-react-native: 6.6.0 => 6.6.0 react: 18.2.0 => 18.2.0 react-dom: 18.2.0 => 18.2.0 react-native: 0.73.5 => 0.73.5 react-native-autocomplete-dropdown: ^3.1.4 => 3.1.4 react-native-base64: ^0.2.1 => 0.2.1 react-native-blurhash: ^1.1.11 => 1.1.11 react-native-bouncy-checkbox: ^3.0.7 => 3.0.7 react-native-circular-progress: ^1.3.9 => 1.3.9 react-native-collapsible: ^1.6.1 => 1.6.1 react-native-figma-squircle: ^0.3.4 => 0.3.4 react-native-gesture-handler: ~2.15.0 => 2.15.0 react-native-get-random-values: ~1.10.0 => 1.10.0 react-native-iconly: ^1.0.12 => 1.0.12 react-native-keyboard-aware-scroll-view: ^0.9.5 => 0.9.5 react-native-maps: 1.10.3 => 1.10.3 react-native-modal: ^13.0.1 => 13.0.1 react-native-pager-view: 6.2.3 => 6.2.3 react-native-pinchable: ^0.2.1 => 0.2.1 react-native-reanimated: ~3.7.1 => 3.7.1 react-native-reanimated-carousel: ^3.5.1 => 3.5.1 react-native-redash: ^18.1.3 => 18.1.3 (12.6.1) react-native-safe-area-context: 4.8.2 => 4.8.2 react-native-screens: ~3.29.0 => 3.29.0 react-native-sqlite-storage: ^6.0.1 => 6.0.1 react-native-svg: 14.1.0 => 14.0.0 react-native-swiper: ^1.6.0 => 1.6.0 react-native-ui-lib: ^7.16.0 => 7.16.0 react-native-web: ~0.19.10 => 0.19.10 react-native-web-maps: ^0.3.0 => 0.3.0 react-test-renderer: 18.2.0 => 18.2.0 typescript: ^5.3.3 => 5.3.3 uilib-native: 4.1.2 zustand: ^4.5.1 => 4.5.1 npmGlobalPackages: @aws-amplify/cli: 12.10.0 corepack: 0.23.0 npm: 10.2.4 yarn: 1.22.21 ```

Describe the bug

I'm developing a React Native application that handles user authentication using AWS Cognito. After a user logs in via Cognito, I use DataStore.query to fetch their information from AWS Amplify DataStore. If no information is found, it indicates the user is new, and we proceed to onboarding. Otherwise, the existing information is retrieved and displayed.

This process works correctly on the first login. However, after logging out and attempting to log in with a different user account, using DataStore.clear() to clear local data, an issue occurs. When I execute DataStore.query to fetch the new user's information, the query returns null on the first attempt, even though the user's data exists in the database.

Expected behavior

Expected behavior The new user's information should be correctly fetched after executing DataStore.query following re-login and the DataStore.clear() call.

Current Behavior The first attempt to fetch the new user's information via DataStore.query returns null, despite the user's data being present in the database.

Reproduction steps

  1. Log in a user via AWS Cognito.
  2. Fetch the user's information by executing DataStore.query(...).
  3. Log out the user.
  4. Use DataStore.clear() to clear local data.
  5. Log in with a different user or the same user.
  6. Attempt to fetch the new user's information again by executing DataStore.query

Code Snippet

No response

Log output

No response

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

Glognus commented 8 months ago

@cwomack do you need more information? Or is there a team dedicated to react native that could take care of this problem? this problem seems to have existed for several months without really having been noticed on react native. Thanks ;)

cwomack commented 8 months ago

Hey, @Glognus and thanks for creating this issue. Just wanted to clarify how you're authenticating in your app. Is it just via a basic authentication flow (username/email and password) or is there any additional steps when signing up/signing in with a user that you're doing?

Also, can you provide any sample code snippets for the DataStore API calls that you're making? Thanks!

cwomack commented 8 months ago

Also, can you clarify if you're using owner auth as well as what identifier you're using to save/query for the user records? Thanks!

Glognus commented 8 months ago

Hi @cwomack , thanks for your reply, i'm using signInWithRedirect cause i'm using social provider (google, facebook, apple) Here is a sample for the auth :

  1. Trigger sign in :

    const signInWithSocialProvider = async (
    provider: SignInWithRedirectInput
    ) => {
    try {
      setLoadingAuthSignIn(true);
      await signInWithRedirect({
        provider: provider.provider,
        options: {
          preferPrivateSession: true,
        },
      });
    } catch (error) {
      console.error("Error signing in with social provider:", error);
    } finally {
      setLoadingAuthSignIn(false);
    }
    };
  2. Listen for Auth event

    const authListener = Hub.listen("auth", (data) => {
      switch (data?.payload?.event) {
        case "signedIn":
          getAuthenticatedUser();
          break;
       ...
      }
    });
  1. Call getAuthenticatedUSer to set the current session if not exist :

    const getAuthenticatedUser = async () => {
    try {
      setLoadingUserAuth(true);
    
      const user = await getCurrentUser();
      setAuth(user);
      await getUserProfile(user); // fetch user profile from Datastore
    
    } catch (error) {
      ...
    } finally {
      setLoadingUserAuth(false);
    }
    };
  2. Fetch user profile from Datastore :


  const getUserProfile = async (auth: AuthUser | null) => {
    try {
      setLoadingProfile(true);

      const authUserId = auth?.userId;

      if (!authUserId) {
        throw new Error(`Auth user id not found`);
      }

      const users = await DataStore.query(User, (u) =>
        u.socialProviderUserName.eq(authUserId)
      );

      const user = users[0];

      if (!user) {
        console.log("User profile not found");

        return router.navigate("/onboarding");
      }
      await fetchAllUserProfile(user);
    } catch (error) {
      ...
    } finally {
      setLoadingProfile(false); 
    }
  };

Here is a sample of my graphql schema :

type User @model @auth(rules: [{ allow: private }, { allow: owner }]) {
  id: ID!
  name: String!
  phone: AWSPhone
  email: AWSEmail
  hasCompletedOnboarding: Boolean
  socialProviderUserName: String
...
}

Please feel free to share your feedback if you believe my approach is appropriate, or if you think a different approach would be better. I sincerely thank you for your assistance.

chrisbonifacio commented 7 months ago

Hey @Glognus thanks for raising this issue. It seems that you might be running into a race condition where, after clearing the local store and logging in again you are querying for a specific record before it might have synced. I would try delaying the query until the "ready" event has been emitted from the DataStore hub events. Or, you can use observeQuery instead to query for and re-render when the user record has been synced.

Glognus commented 7 months ago

Thanks for your feedback, i will take a look

david-mcafee commented 6 months ago

@Glognus - have you had a chance to implement @chrisbonifacio's suggestion above? Thank you!

Glognus commented 6 months ago

I have not had the opportunity to reproduce this problem, I prefer to close this issue, thank you anyway !