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.39k stars 2.11k forks source link

Pinpoint endpoint user ID keeps getting set to identityId #13174

Closed nigelAt8Seats closed 1 month ago

nigelAt8Seats commented 3 months ago

Before opening, please confirm:

JavaScript Framework

React Native

Amplify APIs

Analytics, Push Notifications

Amplify Version

v6

Amplify Categories

analytics, notifications

Backend

Amplify CLI

Environment information

``` # Put output below this line npx envinfo --system --binaries --browsers --npmPackages --duplicates --npmGlobalPackages System: OS: Linux 6.2 Ubuntu 22.04.4 LTS 22.04.4 LTS (Jammy Jellyfish) CPU: (8) x64 Intel(R) Core(TM) i7-10510U CPU @ 1.80GHz Memory: 12.59 GB / 31.18 GB Container: Yes Shell: 5.1.16 - /bin/bash Binaries: Node: 18.18.2 - ~/.asdf/installs/nodejs/18.18.2/bin/node Yarn: 1.22.21 - ~/code/8/horizons/node_modules/.bin/yarn npm: 9.8.1 - ~/.asdf/plugins/nodejs/shims/npm Browsers: Chrome: 122.0.6261.128 npmPackages: @aws-amplify/react-native: ^1.0.5 => 1.0.13 @aws-amplify/rtn-push-notification: ^1.2.5 => 1.2.13 @babel/core: ^7.20.0 => 7.23.9 @babel/preset-env: ^7.20.0 => 7.23.9 @babel/runtime: ^7.20.0 => 7.23.9 @gorhom/bottom-sheet: ^4.4.7 => 4.6.0 @hookform/resolvers: ^3.1.1 => 3.3.4 @hookform/resolvers/ajv: 1.0.0 @hookform/resolvers/arktype: 1.0.0 @hookform/resolvers/class-validator: 1.0.0 @hookform/resolvers/computed-types: 1.0.0 @hookform/resolvers/io-ts: 1.0.0 @hookform/resolvers/joi: 1.0.0 @hookform/resolvers/nope: 1.0.0 @hookform/resolvers/superstruct: 1.0.0 @hookform/resolvers/typanion: 1.0.0 @hookform/resolvers/typebox: 1.0.0 @hookform/resolvers/valibot: 1.0.0 @hookform/resolvers/vest: 1.0.0 @hookform/resolvers/yup: 1.0.0 @hookform/resolvers/zod: 1.0.0 @jest/globals: ^29.6.1 => 29.7.0 @react-native-async-storage/async-storage: ^1.22.3 => 1.21.0 @react-native-clipboard/clipboard: ^1.13.1 => 1.13.2 @react-native-community/blur: ^4.3.2 => 4.4.0 @react-native-community/checkbox: ^0.5.16 => 0.5.17 @react-native-community/netinfo: ^11.1.0 => 11.2.1 @react-native-picker/picker: ^2.4.10 => 2.6.1 @react-native-segmented-control/segmented-control: ^2.4.2 => 2.5.0 @react-native/eslint-config: ^0.73.2 => 0.72.2 @react-native/metro-config: ^0.73.5 => 0.72.11 @react-navigation/bottom-tabs: ^6.5.7 => 6.5.11 @react-navigation/drawer: ^6.6.3 => 6.6.6 @react-navigation/native: ^6.1.6 => 6.1.9 @react-navigation/native-stack: ^6.9.12 => 6.9.17 @shopify/flash-list: ^1.6.1 => 1.6.3 @testing-library/jest-dom: ^6.1.5 => 6.4.0 @testing-library/jest-native: ^5.4.3 => 5.4.3 @testing-library/react-native: ^12.4.1 => 12.4.3 @types/jest: ^29.5.3 => 29.5.11 @types/lodash: ^4.14.199 => 4.14.202 @types/luxon: ^3.3.2 => 3.4.2 @types/node: ^20.10.3 => 20.11.10 @types/react: ^18.2.6 => 18.2.48 @types/react-native-base64: ^0.2.0 => 0.2.2 @types/react-test-renderer: ^18.0.0 => 18.0.7 @types/uuid: ^9.0.2 => 9.0.8 HelloWorld: 0.0.1 add: ^2.0.6 => 2.0.6 appcenter: ^4.4.5 => 4.4.5 appcenter-analytics: ^4.4.5 => 4.4.5 appcenter-crashes: ^4.4.5 => 4.4.5 aws-amplify: ^6.0.6 => 6.0.13 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 () aws-sdk: ^2.1510.0 => 2.1546.0 babel-jest: ^29.6.3 => 29.7.0 babel-plugin-module-resolver: ^5.0.0 => 5.0.0 core-js: ^3.35.1 => 3.35.1 (1.2.7) emoji-regex: ^10.2.1 => 10.3.0 (9.2.2, 6.4.2, 8.0.0) emoji-utils: ^1.0.1 => 1.0.1 eslint: ^8.19.0 => 8.56.0 eslint-plugin-import: ^2.29.1 => 2.29.1 eslint-plugin-sort-destructure-keys: ^1.5.0 => 1.5.0 eslint-plugin-sort-keys-fix: ^1.1.2 => 1.1.2 eslint-plugin-typescript-sort-keys: ^3.1.0 => 3.1.0 exponential-backoff: ^3.1.1 => 3.1.1 husky: ^8.0.0 => 8.0.3 i18next: ^23.2.3 => 23.8.1 immer: 9.0.6 => 9.0.6 ini: ^1.3.5 => 1.3.8 inquirer: ^6.5.1 => 6.5.2 intl-pluralrules: ^2.0.1 => 2.0.1 jest: ^29.6.3 => 29.7.0 libphonenumber-js: ^1.10.44 => 1.10.54 libphonenumber-js/build: undefined () libphonenumber-js/core: undefined () libphonenumber-js/max: undefined () libphonenumber-js/max/metadata: undefined () libphonenumber-js/min: undefined () libphonenumber-js/min/metadata: undefined () libphonenumber-js/mobile: undefined () libphonenumber-js/mobile/examples: undefined () libphonenumber-js/mobile/metadata: undefined () lodash: ^4.17.21 => 4.17.21 lottie-react-native: ^5.1.6 => 5.1.6 luxon: ^3.4.3 => 3.4.4 mitt: ^3.0.1 => 3.0.1 moment: ^2.29.4 => 2.30.1 moment-timezone: ^0.5.43 => 0.5.44 patch-package: ^7.0.0 => 7.0.2 postinstall-postinstall: ^2.1.0 => 2.1.0 prettier: ^2.8.8 => 2.8.8 (3.2.4) react: 18.2.0 => 18.2.0 react-hook-form: ^7.45.0 => 7.49.3 react-i18next: ^13.0.1 => 13.5.0 react-native: 0.73.5 => 0.72.8 react-native-avoid-softinput: ^4.0.0 => 4.0.2 react-native-base64: ^0.2.1 => 0.2.1 react-native-blob-util: ^0.19.6 => 0.19.6 react-native-bootsplash: ^5.0.2 => 5.3.0 react-native-bundle-visualizer: ^3.1.0 => 3.1.3 react-native-clean-project: ^4.0.1 => 4.0.3 react-native-compressor: ^1.6.1 => 1.8.23 react-native-config: ^1.5.1 => 1.5.1 react-native-confirmation-code-field: ^7.3.1 => 7.3.2 react-native-contacts: ^7.0.7 => 7.0.8 react-native-date-picker: ^4.2.13 => 4.3.5 react-native-device-info: ^10.8.0 => 10.12.0 react-native-fast-image: ^8.6.3 => 8.6.3 react-native-gesture-handler: ^2.12.0 => 2.14.1 react-native-get-random-values: ^1.9.0 => 1.10.0 react-native-gifted-chat: ^2.4.0 => 2.4.0 react-native-haptic-feedback: ^2.2.0 => 2.2.0 react-native-image-picker: ^5.6.0 => 5.7.0 react-native-inappbrowser-reborn: ^3.7.0 => 3.7.0 react-native-keyboard-controller: ^1.5.6 => 1.10.4 react-native-linear-gradient: ^2.6.2 => 2.8.3 react-native-localize: ^3.0.2 => 3.0.6 react-native-markdown-display: 7.0.0-alpha.2 => 7.0.0-alpha.2 react-native-mask-input: ^1.2.3 => 1.2.3 react-native-mmkv: ^2.9.0 => 2.11.0 react-native-pager-view: ^6.2.2 => 5.4.25 react-native-reanimated: 3.7.2 => 3.3.0 react-native-reanimated-carousel: ^3.5.1 => 3.5.1 react-native-safe-area-context: ^4.5.3 => 4.8.2 react-native-screens: ^3.21.0 => 3.29.0 react-native-section-list-get-item-layout: ^2.2.3 => 2.2.3 react-native-share: ^10.0.2 => 10.0.2 react-native-snap-carousel: ^3.9.1 => 3.9.1 react-native-svg: ^13.9.0 => 13.14.0 react-native-svg-transformer: ^1.0.0 => 1.3.0 react-native-tracking-transparency: ^0.1.2 => 0.1.2 react-native-url-polyfill: ^2.0.0 => 2.0.0 react-native-version: ^4.0.0 => 4.0.0 react-native-vision-camera: ^3.8.2 => 3.8.2 react-native-webview: ^13.2.2 => 13.6.4 react-phone-number-input: ^3.2.25 => 3.3.9 react-phone-number-input/commonjs: undefined () react-phone-number-input/core: undefined () react-phone-number-input/flags: undefined () react-phone-number-input/input-core: undefined () react-phone-number-input/input-max: undefined () react-phone-number-input/input-min: undefined () react-phone-number-input/input-mobile: undefined () react-phone-number-input/max: undefined () react-phone-number-input/min: undefined () react-phone-number-input/mobile: undefined () react-phone-number-input/react-hook-form: undefined () react-phone-number-input/react-hook-form-core: undefined () react-phone-number-input/react-hook-form-input: undefined () react-phone-number-input/react-hook-form-input-core: undefined () react-phone-number-input/react-native-input: undefined () react-phone-number-input/react-styleguidist: undefined () react-test-renderer: ^18.2.0 => 18.2.0 regenerator-runtime: ^0.14.1 => 0.13.11 (0.14.1) rive-react-native: ^6.2.3 => 4.1.2 superjson: ^2.2.1 => 2.2.1 ts-jest: ^29.1.1 => 29.1.2 typescript: 5.0.4 => 4.8.4 uuid: ^9.0.0 => 9.0.1 (8.3.2, 8.0.0, 3.4.0) yarn: ^1.22.19 => 1.22.21 yup: ^1.2.0 => 1.3.3 yup-phone-lite: ^2.0.1 => 2.0.1 zustand: ^4.4.4 => 4.5.0 npmGlobalPackages: @aws-amplify/cli: 12.10.1 corepack: 0.19.0 npm: 9.8.1 yarn: 1.22.21 ```

Describe the bug

React Native app. We send pinpoint push notifications and analytics.

We PushNotifications.identitfyUser as soon as we have the cognito sub. We always use the cognito sub. Logging shows we never call it incorrectly... but the endpoints keeps getting their user id set to the identityId. This breaks notifications as we can't look up the endpoints using the user id any more.

I've experimented with turning off all the analytics I can. I can still create the problem intermittently by minimising the app while it's loading... before the user id has been set.

Expected behavior

The user id in the endpoints should stay set to the cognito user id.

Reproduction steps

I can still create the problem intermittently by minimising the app while it's loading... before the user id has been set.

Code Snippet

// Put your code below this line.

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

cwomack commented 3 months ago

Hey there, @nigelAt8Seats and thank you for opening this issue. To better understand what's happening here, do you have some frontend code you can share that details how/where you're calling identitfyUser()? And is this happening with every user within your app or just intermittently after you tried to remove Analytics?

nigelAt8Seats commented 3 months ago

Hiya, I believe our code is the equivalent to that in the react-native documentation.


const CognitoUserProvider = ({ children }: { children: ReactNode }) => {
  const [cognitoUser, setCognitoUser] = useState<AuthUser | undefined>();
  const { showNoConnection } = useShowNoConnection(cognitoUser);

  const { deviceToken } = useContext(DeviceTokenContext);

  const checkForLoggedInUser = useCallback(async () => {
    const user = await getCurrentUser().catch(() => null);
    logger.debug('>>>>>>>>> user::', user);
    if (user) {
      setCognitoUser(user);
      logger.debug('bootstrapping user session successful.');
    } else {
      setCognitoUser(undefined);
    }
  }, [setCognitoUser]);

  useEffect(() => {
    if (cognitoUser) {
      const identifyUserInput: IdentifyUserInput = {
        // E.g. user-id
        options: {
          address: deviceToken,
          optOut: 'NONE', // Either ALL or NONE
        },
        userId: cognitoUser.userId,
        userProfile: {},
      };

      identifyUser(identifyUserInput);
      postHogTrack('New Device Token Received', {
        user: cognitoUser?.userId ?? '',
        token: deviceToken ?? '',
      });
      logger.debug('identifying user successful');
    }
  }, [cognitoUser, deviceToken]);

  useEffect(() => {
    checkForLoggedInUser()
      .catch((err: any) => {
        logger.warn('warn::checkForLoggedInUser::', err);
        setCognitoUser(undefined);
      })
      .finally(() => {
        BootSplash.hide({ fade: true });
      });
  }, [checkForLoggedInUser]);

  return (
    <CognitoUserContext.Provider
      value={{
        checkForLoggedInUser,
        cognitoUser,
        setCognitoUser,
      }}>
      {showNoConnection ? <NoConnection /> : children}
    </CognitoUserContext.Provider>
  );
};

export default CognitoUserProvider;

We have a cognito user provider.

export const DeviceTokenContext = createContext<{
  deviceToken?: string;
}>({
  deviceToken: undefined,
});

export const DeviceTokenProvider = ({ children }: { children: ReactNode }) => {
  const [deviceToken, setDeviceToken] = useState<string | undefined>();

  useEffect(() => {
    const tokenListener = onTokenReceived(async token => {
      logger.debug('deviceTokenProvider:: token received:', token);

      setDeviceToken(token);
    });

    return () => {
      tokenListener.remove();
    };
  }, [setDeviceToken]);

  return (
    <DeviceTokenContext.Provider value={{ deviceToken }}>
      {children}
    </DeviceTokenContext.Provider>
  );
};
#also

  const initSignIn = async () => {
    const user = await getCurrentUser();
    logger.debug('user', user);

    const localUserId = await AsyncStorage.getItem('8seats::userId');
    if (localUserId !== user.userId) {
      await DataStore.clear();
      await AsyncStorage.setItem('8seats::userId', user.userId);
    }

    const identifyUserInput: IdentifyUserInput = {
      // E.g. user-id
      options: {
        optOut: 'NONE', // Either ALL or NONE
      },
      userId: user.userId,
      userProfile: {},
    };

    await identifyUser(identifyUserInput);
    return user;
  };

The problem has existed for months... Turning off Analytics has made it less frequent; but still possible.

nigelAt8Seats commented 3 months ago

Disabling analytics

disable(); // analytics

Amplify.configure(amplifyconfig); # << I took all the analytics stuff out of the config too. 

configureAutoTrack({
  enable: false,
  type: 'session', # << react native so autotracking is only for session 
});

initializePushNotifications();

// also called when the process is Terminated
onNotificationReceivedInBackground(
  NotificationsService.onNotificationReceivedInBackgroundOrTerminatedHandler,
);
cwomack commented 3 months ago

@nigelAt8Seats, appreciate the sample code. Just to confirm, is this all areas where identifyUser() is called?

cwomack commented 2 months ago

Updating this issue to be a bug and we are actively investigating this further. It looks like the root problem is with the UpdateEndpoint util in core where we are using a fallback value that changes what is set when calling an API like identifyUser().

We'll update this issue as we make progress.

cshfang commented 1 month ago

Hi @nigelAt8Seats

Amplify JS v6.3.1 has just been released. It should contain the following fixes: https://github.com/aws-amplify/amplify-js/issues/13174 https://github.com/aws-amplify/amplify-js/pull/13353

We believe these fixes should resolve your issue of the endpoint being overwritten by the device registration. Could you please help us by verifying if this is indeed the case by updating to the latest Amplify version? Thank you

nigelAt8Seats commented 1 month ago

We moved to using firebase cloud messaging instead of pinpoint to avoid the issue entirely.

cwomack commented 1 month ago

@nigelAt8Seats, we appreciate the follow up comment and will close the issue as resolved at this point. Feel free to let us know if you're able to validate fixes and come back to Analytics/Pinpoint at any time!