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

Error when calling currentAuthenticatedUser() #8485

Closed pgbradbury closed 3 years ago

pgbradbury commented 3 years ago

Before opening, please confirm:

JavaScript Framework

React, Next.js

Amplify APIs

Authentication

Amplify Categories

auth

Environment information

``` # Put output below this line System: OS: macOS 11.3.1 CPU: (4) x64 Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz Memory: 80.92 MB / 8.00 GB Shell: 3.2.57 - /bin/bash Binaries: Node: 15.7.0 - /usr/local/bin/node Yarn: 1.22.10 - /usr/local/bin/yarn npm: 7.4.3 - /usr/local/bin/npm Browsers: Chrome: 91.0.4472.106 Safari: 14.1 npmPackages: @ampproject/toolbox-optimizer: undefined () @aws-amplify/ui-components: ^1.3.1 => 1.4.0 @aws-amplify/ui-react: ^1.2.0 => 1.2.2 @babel/core: undefined () @babel/eslint-parser: ^7.12.1 => 7.14.5 @babel/eslint-plugin: ^7.12.13 => 7.14.5 @babel/plugin-transform-react-jsx: ^7.10.4 => 7.14.5 @babel/preset-env: ^7.10.4 => 7.14.5 @babel/preset-react: ^7.10.4 => 7.14.5 @fullstory/babel-plugin-annotate-react: ^2.1.0 => 2.1.2 @fullstory/browser: ^1.4.9 => 1.4.9 @lambdatest/node-tunnel: ^3.0.0 => 3.0.1 @material-ui/core: ^4.11.0 => 4.11.4 @material-ui/icons: ^4.9.1 => 4.11.2 @material-ui/lab: ^4.0.0-alpha.56 => 4.0.0-alpha.58 @material-ui/pickers: ^4.0.0-alpha.12 => 4.0.0-alpha.12 (3.2.2) @material-ui/pickers-adapter-date-fns: undefined () @material-ui/pickers-adapter-dayjs: undefined () @material-ui/pickers-adapter-luxon: undefined () @material-ui/pickers-adapter-moment: undefined () @reduxjs/toolkit: ^1.6.0 => 1.6.0 @reduxjs/toolkit-query: 1.0.0 @reduxjs/toolkit-query-react: 1.0.0 @sentry/fullstory: ^1.1.5 => 1.1.5 @sentry/nextjs: ^6.7.0 => 6.7.1 @testing-library/jest-dom: 4.2.4 => 4.2.4 @testing-library/react: ^11.2.5 => 11.2.7 @testing-library/react-hooks: ^5.0.3 => 5.1.3 @types/jest: ^26.0.5 => 26.0.23 @types/material-ui: ^0.21.8 => 0.21.8 @types/node: ^14.14.33 => 14.17.3 (15.12.2, 11.15.54) @types/react: ^17.0.2 => 17.0.11 @types/react-dom: ^17.0.2 => 17.0.7 @typescript-eslint/eslint-plugin: ^4.14.2 => 4.27.0 @typescript-eslint/parser: ^4.14.2 => 4.27.0 @wojtekmaj/enzyme-adapter-react-17: ^0.4.1 => 0.4.1 amphtml-validator: undefined () amplify-ui-components-loader: undefined () arg: undefined () async-retry: undefined () async-sema: undefined () aws-amplify: ^4.0.2 => 4.1.0 axios: ^0.21.1 => 0.21.1 (0.19.2) babel-jest: ^26.1.0 => 26.6.3 bfj: undefined () cacache: undefined () chromedriver: ^85.0.1 => 85.0.1 ci-info: undefined () comment-json: undefined () compression: undefined () conf: undefined () content-type: undefined () cookie: undefined () css-loader: undefined () date-fns: ^2.21.3 => 2.22.1 (2.0.0-alpha.27) debug: undefined () devalue: undefined () enzyme: ^3.11.0 => 3.11.0 escape-string-regexp: undefined () eslint: ^7.19.0 => 7.28.0 eslint-config-prettier: ^7.2.0 => 7.2.0 eslint-plugin-babel: ^5.3.1 => 5.3.1 eslint-plugin-i18next: ^5.0.0 => 5.1.1 eslint-plugin-jest: ^24.1.3 => 24.3.6 eslint-plugin-jsx-a11y: ^6.4.1 => 6.4.1 eslint-plugin-prettier: ^3.3.1 => 3.4.0 eslint-plugin-react: ^7.22.0 => 7.24.0 eslint-plugin-react-hooks: ^4.2.0 => 4.2.0 eslint-plugin-react-perf: ^3.3.0 => 3.3.0 eslint-plugin-sonarjs: ^0.5.0 => 0.5.0 eslint-plugin-unicorn: ^27.0.0 => 27.0.0 file-loader: undefined () find-cache-dir: undefined () find-up: undefined () fresh: undefined () gzip-size: undefined () http-proxy: undefined () i18next: ^19.8.9 => 19.9.2 ignore-loader: undefined () is-animated: undefined () is-docker: undefined () is-wsl: undefined () isomorphic-fetch: ^3.0.0 => 3.0.0 jest: ^26.1.0 => 26.6.3 jest-cucumber: ^3.0.0 => 3.0.1 jest-junit: ^11.1.0 => 11.1.0 jest-sonar-reporter: ^2.0.0 => 2.0.0 json5: undefined () jsonwebtoken: undefined () loader-utils: undefined () lodash.curry: undefined () lru-cache: undefined () material-table: ^1.69.1 => 1.69.3 md5: ^2.3.0 => 2.3.0 mini-css-extract-plugin: undefined () moxios: ^0.4.0 => 0.4.0 nanoid: undefined () neo-async: undefined () next: ^10.2.1 => 10.2.3 next-redux-wrapper: ^7.0.2 => 7.0.2 ora: undefined () postcss-flexbugs-fixes: undefined () postcss-loader: undefined () postcss-preset-env: undefined () postcss-scss: undefined () prettier: ^2.2.1 => 2.3.1 prop-types: ^15.7.2 => 15.7.2 (15.6.2) react: ^17.0.1 => 17.0.2 react-dom: ^17.0.1 => 17.0.2 react-dropzone: ^11.3.1 => 11.3.2 react-feather: ^2.0.8 => 2.0.9 react-i18next: ^11.8.9 => 11.11.0 react-image: ^4.0.2 => 4.0.3 react-redux: ^7.2.4 => 7.2.4 react-test-renderer: ^16.14.0 => 16.14.0 (17.0.2) react-vis: ^1.11.7 => 1.11.7 recast: undefined () redux-devtools-extension: ^2.13.9 => 2.13.9 redux-saga: ^1.1.3 => 1.1.3 redux-saga/effects: undefined () resolve-url-loader: undefined () sass-loader: undefined () schema-utils: undefined () selenium-webdriver: ^4.0.0-alpha.7 => 4.0.0-beta.4 semver: undefined () send: undefined () source-map: undefined () string-hash: undefined () strip-ansi: undefined () styled-components: ^5.3.0 => 5.3.0 styled-components/macro: undefined () styled-components/native: undefined () styled-components/primitives: undefined () terser: undefined () text-table: undefined () ts-node: ^9.1.1 => 9.1.1 typescript: ^4.2.3 => 4.3.3 unistore: undefined () web-vitals: undefined () webpack: undefined () webpack-sources: undefined () with-typescript: undefined () npmGlobalPackages: @aws-amplify/cli: 4.51.2 npm: 7.4.3 ```

Describe the bug

AWS Support asked me to raise this here as they can't find a solution and will escalate to you.

I am building a Typescript/Next.js/React/Redux app and I am trying to pass the user object via the props from the _app.tsx page

I get a The user is not authenticated error when calling currentAuthenticatedUser(). I am not using federated login.

Expected behavior

The user object is returned with the logged in user.

Reproduction steps

It happens as soon as you navigate to the base URL of the app.

Code Snippet

// Put your code below this line.
import React from "react"
import App, { AppInitialProps, AppContext } from "next/app"
import Amplify, { Auth, withSSRContext } from "aws-amplify"
import { CognitoUserInterface } from "@aws-amplify/ui-components"
import { AmplifyAuthenticator, AmplifySignIn } from "@aws-amplify/ui-react"
import { CssBaseline, ThemeProvider } from "@material-ui/core/"

import { config } from "../amplify.config"
import RadiateTheme from "../components/RadiateTheme"
import { wrapper } from "../state/store"

Amplify.configure({ ...config, ssr: true })

class Aura extends App<AppInitialProps> {
    public static getInitialProps = wrapper.getInitialAppProps(
        (store) =>
            async ({ Component, ctx }: AppContext) => {
                const auth = withSSRContext(ctx).Auth as typeof Auth
                const user: CognitoUserInterface =
                    await auth.currentAuthenticatedUser()
                store.dispatch({ type: "SETUSER", payload: user })
                return {
                    pageProps: {
                        ...(Component.getInitialProps
                            ? await Component.getInitialProps({
                                  ...ctx,
                                  store,
                              })
                            : {}),
                    },
                }
            }
    )
    public render() {
        const { Component, pageProps } = this.props

        return (
            <ThemeProvider theme={RadiateTheme}>
                <CssBaseline />
                <AmplifyAuthenticator>
                    <AmplifySignIn
                        hideSignUp
                        usernameAlias="email"
                        slot="sign-in"
                    />
                    <Component {...pageProps} />
                </AmplifyAuthenticator>
            </ThemeProvider>
        )
    }
}

export default wrapper.withRedux(Aura)

Log output

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

aws-exports.js

export const config = {
    aws_project_region: "eu-west-1",
    aws_cognito_identity_pool_id:
        "eu-west-1:xxx",
    aws_cognito_region: "eu-west-1",
    aws_user_pools_id: "eu-west-1_xxx",
    aws_user_pools_web_client_id: "xxx",
    oauth: {},
}

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

  1. AWS technical support couldn't solve and I still have a ticket open with them
  2. If you hard code the user object the code works as expected

Package.json is the following

"dependencies": {
        "@aws-amplify/ui-components": "^1.3.1",
        "@aws-amplify/ui-react": "^1.2.0",
        "@fullstory/browser": "^1.4.9",
        "@material-ui/core": "^4.11.0",
        "@material-ui/icons": "^4.9.1",
        "@material-ui/lab": "^4.0.0-alpha.56",
        "@material-ui/pickers": "^4.0.0-alpha.12",
        "@reduxjs/toolkit": "^1.6.0",
        "@sentry/fullstory": "^1.1.5",
        "@sentry/nextjs": "^6.7.0",
        "@types/material-ui": "^0.21.8",
        "@types/node": "^14.14.33",
        "@types/react": "^17.0.2",
        "@types/react-dom": "^17.0.2",
        "aws-amplify": "^4.0.2",
        "axios": "^0.21.1",
        "date-fns": "^2.21.3",
        "i18next": "^19.8.9",
        "material-table": "^1.69.1",
        "md5": "^2.3.0",
        "next": "^10.2.1",
        "next-redux-wrapper": "^7.0.2",
        "prop-types": "^15.7.2",
        "react": "^17.0.1",
        "react-dom": "^17.0.1",
        "react-dropzone": "^11.3.1",
        "react-feather": "^2.0.8",
        "react-i18next": "^11.8.9",
        "react-image": "^4.0.2",
        "react-redux": "^7.2.4",
        "react-vis": "^1.11.7",
        "redux-devtools-extension": "^2.13.9",
        "redux-saga": "^1.1.3",
        "styled-components": "^5.3.0"
    },
    "devDependencies": {
        "@babel/eslint-parser": "^7.12.1",
        "@babel/eslint-plugin": "^7.12.13",
        "@babel/plugin-transform-react-jsx": "^7.10.4",
        "@babel/preset-env": "^7.10.4",
        "@babel/preset-react": "^7.10.4",
        "@fullstory/babel-plugin-annotate-react": "^2.1.0",
        "@lambdatest/node-tunnel": "^3.0.0",
        "@testing-library/jest-dom": "4.2.4",
        "@testing-library/react": "^11.2.5",
        "@testing-library/react-hooks": "^5.0.3",
        "@types/jest": "^26.0.5",
        "@typescript-eslint/eslint-plugin": "^4.14.2",
        "@typescript-eslint/parser": "^4.14.2",
        "@wojtekmaj/enzyme-adapter-react-17": "^0.4.1",
        "babel-jest": "^26.1.0",
        "chromedriver": "^85.0.1",
        "enzyme": "^3.11.0",
        "eslint": "^7.19.0",
        "eslint-config-prettier": "^7.2.0",
        "eslint-plugin-babel": "^5.3.1",
        "eslint-plugin-i18next": "^5.0.0",
        "eslint-plugin-jest": "^24.1.3",
        "eslint-plugin-jsx-a11y": "^6.4.1",
        "eslint-plugin-prettier": "^3.3.1",
        "eslint-plugin-react": "^7.22.0",
        "eslint-plugin-react-hooks": "^4.2.0",
        "eslint-plugin-react-perf": "^3.3.0",
        "eslint-plugin-sonarjs": "^0.5.0",
        "eslint-plugin-unicorn": "^27.0.0",
        "isomorphic-fetch": "^3.0.0",
        "jest": "^26.1.0",
        "jest-cucumber": "^3.0.0",
        "jest-junit": "^11.1.0",
        "jest-sonar-reporter": "^2.0.0",
        "moxios": "^0.4.0",
        "prettier": "^2.2.1",
        "react-test-renderer": "^16.14.0",
        "selenium-webdriver": "^4.0.0-alpha.7",
        "ts-node": "^9.1.1",
        "typescript": "^4.2.3"
    },
chrisbonifacio commented 3 years ago

Hello @pgbradbury :wave: I think the issue here is that Auth.currentAuthenticatedUser is throwing an error so it's blocking your page and authenticator from rendering because there may not be a user currently logged in at first. I'm not very familiar with TS so I removed all the type references but here's what I did to getInitialProps to get it working. I basically just wrapped auth.currentAuthenticatedUser in a try/catch. This should allow your page to render instead of throwing an error on the server before it gets the chance to render.

static getInitialProps = async ({ Component, ctx }) => {
    const auth = withSSRContext(ctx).Auth;
    try {
      const user = await auth.currentAuthenticatedUser();
      console.log({ user });

      return {
        pageProps: {
          ...(Component.getInitialProps
            ? await Component.getInitialProps({
                ...ctx,
                store,
              })
            : {
                user,
              }),
        },
      };
    } catch (error) {
      console.error(error);
    }
  };

Now when I log in, I get this logged from the server

user: CognitoUser {
    username: 'a042760e-9b68-425d-9ea1-fa2efa783acb',
    pool: CognitoUserPool {
      userPoolId: 'eu-west-1_xxxxxxx',
      clientId: 'xxxxxxxxxxxxxxxxxxxxxx,
      client: [Client],
      advancedSecurityDataCollectionFlag: true,
      storage: [UniversalStorage],
      wrapRefreshSessionCallback: [Function (anonymous)]
    },
    Session: null,
    client: Client {
      endpoint: 'https://cognito-idp.eu-west-1.amazonaws.com/',
      fetchOptions: {}
    },
    signInUserSession: CognitoUserSession {
      idToken: [CognitoIdToken],
      refreshToken: [CognitoRefreshToken],
      accessToken: [CognitoAccessToken],
      clockDrift: 0
    },
    authenticationFlowType: 'USER_SRP_AUTH',
    storage: UniversalStorage {
      cookies: [Cookies],
      store: [Object: null prototype]
    },
    keyPrefix: 'CognitoIdentityServiceProvider.XXXXXXXXXXXXXX',
    userDataKey: 'CognitoIdentityServiceProvider.XXXXXXXXXXXXXXXXXXX.userData',
    attributes: {
      sub: 'a042760e-9b68-425d-9ea1-fa2efa783acb',
      email_verified: true,
      phone_number_verified: false,
      phone_number: '+15558085788',
      email: 'chris.github@gmail.com'
    },
    preferredMFA: 'NOMFA'
  }
},

My page props logged from client

{
  pageProps: {
    user: CognitoUser {
      username: 'a042760e-9b68-425d-9ea1-fa2efa783acb',
      pool: [CognitoUserPool],
      Session: null,
      client: [Client],
      signInUserSession: [CognitoUserSession],
      authenticationFlowType: 'USER_SRP_AUTH',
      storage: [UniversalStorage],
      keyPrefix: 'CognitoIdentityServiceProvider.XXXXXXXXXXXXX',
      userDataKey: 'CognitoIdentityServiceProvider.XXXXXXXXXXXX.userData',
      attributes: [Object],
      preferredMFA: 'NOMFA'
    }
  }
}
pgbradbury commented 3 years ago

Hi,

You seem to have removed the redux wrapper as well. I wrapped the try-catch as you did around my existing code, however I still get an error

I am logging the following

1. getProps created store with state undefined
The user is not authenticated
3. getProps after dispatches has store state undefined
4. WrappedApp created new store with withRedux(_app_Aura) { initialState: undefined, initialStateFromGSPorGSSR: undefined }
props: {
  'data-element': 'Component',
  'data-source-file': '_app.tsx',
  dispatch: [Function: dispatch]
}

I need the initial state to have the user object defined.

pgbradbury commented 3 years ago

Also, the current state of the user is a logged in authenticated user.

chrisbonifacio commented 3 years ago

Ah okay, gotcha. So your app was already able to render the authenticator and you were able to log in through the form but you get this error after logging in? I've yet to use Redux with Next.js and Amplify so I'm not sure if this is an Amplify or Redux issue but I will try to add Redux to my reproduction.

pgbradbury commented 3 years ago

Not exactly, I am building this in a docker container. So I have previously logged in and it's dropped a cookie. I have then rebuilt the container, so the user still persists in the cookie but is dropped from the server. I have tweaked a couple of things (it was throwing an error after this due to no state, I moved that) and it seems to now work with the try-catch solution. I will try some more scenarios, but I think this has fixed it.

chrisbonifacio commented 3 years ago

Nice! Yeah, please let me know if you're able to persist user data to your Redux store. I'll still try to work Redux into my reproduction so I'm more familiar with the design pattern. I'm currently looking through this

https://github.com/vercel/next.js/tree/canary/examples/with-redux

pgbradbury commented 3 years ago

I started there but ended up using a library to help with the redux-nextjs integration

https://github.com/kirill-konshin/next-redux-wrapper

https://github.com/vercel/next.js/tree/canary/examples/with-redux-wrapper

pgbradbury commented 3 years ago

OK, so I have tested this a few different ways. It seems to boil down to this at the moment.

On the first instance of a login the try and catch works, but no user is set, so the app breaks or you catch no user and do something.

If I refresh the app works. I assume this is all tied to amplify SSR logic and figuring out an authenticated user.

A hack would be to force a refresh on catching no user, but that is really bad. I thought the whole point of withSSRContext was to make this work. This is what I have put in place and it works, but its not good code.

Any ideas?

P.S. I upgraded aws-amplify to 4.1.1, it made no difference.

chrisbonifacio commented 3 years ago

I'm thinking since you're using redux and dispatching that action from getInitialProps, maybe you should add the Hub listener from Amplify to a useEffect so the client can dispatch that action that updates the redux store with the current user on a sign in event?

The action from getInitialProps sounds to me like it will only work if the user's already logged in which means credentials have been set to localStorage and/or the cookie exists. So that action would be updating the redux store when a user either reloads the page or comes back to the site at a later time, etc, but that sign in event needs to trigger its own dispatch to the store as well which can be done through the Hub.

pgbradbury commented 3 years ago

Sorry for the late response, I have been trying a few things out.

The problem is that the server-side doesn't seem to be working at all. I can try with a logged-in user or log in from a clean state, either way, it doesn't pick up the user server-side. I am not sure why as I thought withSSRContext (an amplify component) was supposed to do that as a first-class integration into next.js

chrisbonifacio commented 3 years ago

Hi @pgbradbury I can't confidently say that this is an issue with Amplify as I don't have any issues using withSSRContext outside of a redux project. I've cloned the with-redux-wrapper example from the links you shared before and have been messing around with it a bit and while I can get my server side code to log the authenticated user, I haven't figured out how to properly store that data in my redux store and/or get it from the store in my components. So, I'm still trying to figure out how to use Amplify and Next-Redux-Wrapper in tandem myself.

pgbradbury commented 3 years ago

Hi @chrisbonifacio understood, but i'm not sure its redux related. It might be though, I am still working on it too and will post a solution if I find one.

With regards to the Hub listener, this seems to be very similar to redux. The reason I don't think it will work is that it will listen for an auth event. However a user may already be logged in to the application and simply returning a few hours later. No event happens, but the app needs to find the user from the cookie.

pgbradbury commented 3 years ago

@chrisbonifacio this issue seems related, it was bot closed but people are still posting to it. #6555

pgbradbury commented 3 years ago

@chrisbonifacio, OK I have stripped it all back and taken the SSR out. I made the auth call in an index.tsx instead. I am still getting the user not authenticated error, I am getting the following more detailed error from the catch block on the async call.

[ERROR] 51:08.525 AuthError - 
            Error: Amplify has not been configured correctly. 
            The configuration object is missing required auth properties. 
            Did you run `amplify push` after adding auth via `amplify add auth`?
            See https://aws-amplify.github.io/docs/js/authentication#amplify-project-setup for more information

followed by my catch console log

***** ERROR *****: The user is not authenticated

Could you let me know where you are at with this, I have not changed the configuration from when it was working? This github ticket was generated as requested from a paid AWS support ticket and time really is of the essence now as it has been weeks.

Code block from index.tsx

        const getUser = async () =>
            await Auth.currentAuthenticatedUser()
                .then((user: CognitoUserInterface) => {
                    console.log("***** USER2 *****:", user)
                    dispatch({ type: "SETUSER", payload: user })
                })
                .catch((error) => {
                    console.log("***** ERROR *****:", error)
                })
        getUser()

My package.json now looks like this

    "dependencies": {
        "@aws-amplify/auth": "3.4.28",
        "@aws-amplify/core": "^3.8.20",
        "@aws-amplify/interactions": "^4.0.4",
        "@aws-amplify/storage": "^4.2.1",
        "@aws-amplify/ui-components": "^1.3.2",
        "@aws-amplify/ui-react": "^1.0.5",
        "@fullstory/browser": "^1.4.9",
        "@material-ui/core": "^4.11.0",
        "@material-ui/lab": "^4.0.0-alpha.56",
        "@material-ui/pickers": "^4.0.0-alpha.12",
        "@reduxjs/toolkit": "^1.6.0",
        "@sentry/fullstory": "^1.1.5",
        "@sentry/nextjs": "^6.7.0",
        "@types/material-ui": "^0.21.8",
        "@types/node": "^14.14.33",
        "@types/react": "^17.0.2",
        "@types/react-dom": "^17.0.2",
        "axios": "^0.21.1",
        "date-fns": "^2.21.3",
        "i18next": "^19.8.9",
        "material-table": "^1.69.1",
        "md5": "^2.3.0",
        "next": "^11.0.1",
        "next-redux-cookie-wrapper": "^2.0.1",
        "next-redux-wrapper": "^7.0.2",
        "prop-types": "^15.7.2",
        "react": "^17.0.2",
        "react-dom": "^17.0.2",
        "react-dropzone": "^11.3.1",
        "react-feather": "^2.0.8",
        "react-i18next": "^11.8.9",
        "react-image": "^4.0.2",
        "react-redux": "^7.2.4",
        "react-vis": "^1.11.7",
        "redux-devtools-extension": "^2.13.9",
        "redux-saga": "^1.1.3",
        "styled-components": "^5.3.0"
    },
chrisbonifacio commented 3 years ago

@pgbradbury Okay, well this helps to narrow down the root issue. With those package versions I think the issue might actually just be duplicate dependencies between the scoped amplify packages which is usually fixed by simply upgrading all packages. How are you importing and configuring Auth?

I removed aws-amplify and replaced my dependencies with yours. I am importing and configuring like so without issues so far.

import { Auth } from "@aws-amplify/auth";
import { config } from "../amplify.config";

Auth.configure({ ...config });
chrisbonifacio commented 3 years ago

With your dependencies, running the command from this page

resulted in this output, meaning these two are duplicated

@aws-amplify/core
@aws-amplify/ui-components
pgbradbury commented 3 years ago

OK, so how is that happening, on my machine I just ran the command and it only shows

@aws-amplify/core

But it is only defined once in the package.json, the ticket I indicated to you says it fixed the issue by installing a specific version of the auth lib. What versions should be pinned to make this work and why are there conflicting libraries creating breaking changes.

pgbradbury commented 3 years ago

I have upgraded to the latest versions which has removed the duplicates and I am rebuilding to see if that makes a difference.

chrisbonifacio commented 3 years ago

Depending on what versions of the scoped packages you install, they are dependent on different versions of other packages. The latest versions should all be compatible with each other though. This is usually only an issue when incompatible versions of the scoped packages are installed, or trying to use them along with aws-amplify. The Amplify class is designed as a singleton. and should only have one instance, otherwise there will be configuration issues.

chrisbonifacio commented 3 years ago

@pgbradbury just wanted to give you a heads up as I just realized it. You will have to use aws-amplify if using Auth (or any other SSR-supported amplify library) in an SSR context because withSSRContext seems to only be exported from there. None of the scoped packages export it because it's a utility to re-instantiate each package per request.

pgbradbury commented 3 years ago

Hey, still working on this build, please don't tag auto close by a bot, I will respond once I have something, as I said its a paid support ticket.

Thanks for the heads up on the withSSRContext not being in the scoped packages, that seems like an oversight and should be in /core

I have only changed to the scoped packages as that has been suggested by others with this same issue as a possible solution, I was looking for you guys to provide a solution, there are a LOT of posts, tickets, requests relating to similar issues, but none of them seem to have a resolution, a lot just get bot closed. There is clearly an issue here, either in the code or the documentation. I appreciate the help so far but I would expect this to be escalated and resolved by now. This isn't a library that is built by people on their own time as a service to the community, its built by a dedicated team at AWS for which I pay for professional support and that support asked me to log this ticket as an escalation as they could replicate but not resolve.

I have changed the code in so many different ways now it is becoming difficult to understand if the root error is due to a change or the same original issue. Redux is a diversion, it was failing before hitting any redux code. I have now changed the code to try and get something working as you have been unable to resolve the original issue.

chrisbonifacio commented 3 years ago

@pgbradbury Apologies. My intention was not for this to be auto-closed, it would take a week of no response for the stale bot to do so. I labeled it as such more for the notification I get on my project board because I can tell just by looking at the board another comment was made on the issue since the bot removed the label. I prefer it over the email notification because I get so many from github already and I spend most of my time on here anyway.

I agree that the issue must've been occurring even before Redux if you were already getting that Auth has not been configured correctly error. However, I set up my reproduction app with the same Auth configuration you have, basically just used the amplify.config file you provided and everything seemed to work both client and server side.

Unless I could take a look at your project repository, it's not obvious to me where the configuration might need to be corrected. I've seen some have issues with the way Amplify.configure or Auth.configure is being called and the properties set. Maybe that could be part of the problem?

This is the way I did it in _app.js

import { Amplify, Hub, withSSRContext } from "aws-amplify";
import { config } from "../amplify.config";

Amplify.configure({ ...config, ssr: true });

Here's my reproduction app which has no Redux code, just the use of withSSRContext to pass each page the currently authenticated user as a prop. You just need to add the amplify.config file you shared before for it to work. I added two other pages that logs the user from props and shows whether it got the user from the client or the server.

So, the way I saw the problem was that if you're using the Amplify sign in component, you don't get redirected to the next view so you're still on the same page. No request to the server was made for the user that just logged in and we're not storing this data anywhere. What I did was use the Hub to listen for the "signIn" event and set the user locally first just so I can keep the amplify sign in component and still get my user while remaining on the same page. This only happens once. If using a custom sign in form, you could simply redirect to the next page and your server side code should get the user and pass it through pageProps. My getInitialProps function is still getting the user on the server side any time the user navigates to another page after the sign in form has been used.

Let me know if this helps and I apologize again for making it seem like this would be auto-closed.

pgbradbury commented 3 years ago

Thanks will try this out.

I am not clear where the misconfiguration was introduced, for example, did it happen when I moved to the scoped packages.

I did get the code working in the index.tsx, returning a user, so now I'll try and get it working in _app.tsx

This is the call that is now working in index.tsx

        const getUser = async () =>
            await Auth.currentAuthenticatedUser()
                .then((user: CognitoUserInterface) => {
                    dispatch({ type: "SETUSER", payload: user })
                })
                .catch((error) => {
                    console.log("***** ERROR *****:", error)
                })
        getUser()
chrisbonifacio commented 3 years ago

@pgbradbury The Auth configuration issue was likely due to the mismatching versions between the scoped packages. The SSR and user state management was the original and separate issue, I believe. If you're using the Amplify UI components to login, you either need to save the response/user data to state locally or even just reload the page/redirect when the signIn event happens from the Hub listener. Although, it sounded like you didn't want to have to reload the page on signIn, which is why I opted to save the response to local state in my app.

So, it's really just that one time 'signIn' event that needs to be handled before withSSRContext can get who the current authenticated user is from the server on subsequent page requests.

Let me know how it's going and/or if my app/explanation helps to make sense of the sign in flow.

pgbradbury commented 3 years ago

@chrisbonifacio

So I have still been struggling with this massively, so I completely replaced my _app.tsx and index.tsx with yours, with only minor code mods. Which is still the same underlying error.

This is what I got

Server console:

{ error: 'The user is not authenticated' }
{ user: { fromClient: true } }

Client console:

{user: {…}}
user:
fromClient: true
__proto__:
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
propertyIsEnumerable: ƒ propertyIsEnumerable()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
valueOf: ƒ valueOf()
__defineGetter__: ƒ __defineGetter__()
__defineSetter__: ƒ __defineSetter__()
__lookupGetter__: ƒ __lookupGetter__()
__lookupSetter__: ƒ __lookupSetter__()
get __proto__: ƒ __proto__()
set __proto__: ƒ __proto__()
__proto__:
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
propertyIsEnumerable: ƒ propertyIsEnumerable()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
valueOf: ƒ valueOf()
__defineGetter__: ƒ __defineGetter__()
__defineSetter__: ƒ __defineSetter__()
__lookupGetter__: ƒ __lookupGetter__()
__lookupSetter__: ƒ __lookupSetter__()
get __proto__: ƒ __proto__()
set __proto__: ƒ __proto__()

Screenshot: image

chrisbonifacio commented 3 years ago

Sorry to hear that. Would you be willing to jump on a call and take a look at this together? I think it might be easier to explain that way than over gh issues.

pgbradbury commented 3 years ago

That would be amazing. What is the best way to organise that? I am on London time, but I'll happily do a call my evening time if that helps, assuming you are on Pacific time.

chrisbonifacio commented 3 years ago

I'm on the East Coast of the U.S., so EST. I think you might have to go through the internal ticket you opened and set up a meeting through there or we could probably set something up faster if you want to email me at christopher.bonifacio@gmail.com 😄

chrisbonifacio commented 3 years ago

Hey @pgbradbury , just wanted to follow up and see how it's going after our meeting. Let me know if there's anything else I can do to help.

chrisbonifacio commented 3 years ago

@pgbradbury Going to close this issue for now since we were able to address the original issue by handling the thrown error when attempting to get the current Authenticated User when not currently logged in with getInitialProps, as well as making sure the user data is being properly accessed and then passed as a prop, after successful login, to each page component and dispatched to the redux store.

That being said, it was a pleasure to jump on a call with you and work through it together. Please feel free to open a new issue with the details of any new blocker so we can track the different issues we're tackling. Thank you!

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.