amplify-js icon indicating copy to clipboard operation
amplify-js copied to clipboard

Cannot retrieve a new session. Please authenticate.

Open dcfranca opened this issue 3 years ago • 15 comments

Before opening, please confirm:

I have searched for duplicate or closed issues. I have read the guide for submitting bug reports. I have done my best to include a minimal, self-contained set of instructions for consistently reproducing the issue.

JavaScript Framework

React

Amplify APIs

Authentication, GraphQL API, Storage

Amplify Categories

auth, storage, function, api

Environment information

# Put output below this line
❯ npx envinfo --system --binaries --browsers --npmPackages --npmGlobalPackages
npx: installed 1 in 1.315s

  System:
    OS: macOS 11.2.3
    CPU: (8) x64 Intel(R) Core(TM) i5-8257U CPU @ 1.40GHz
    Memory: 220.21 MB / 16.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 14.15.2 - /usr/local/bin/node
    Yarn: 1.22.4 - /usr/local/bin/yarn
    npm: 6.14.9 - /usr/local/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  Browsers:
    Brave Browser: 87.1.18.70
    Chrome: 89.0.4389.114
    Edge: 89.0.774.68
    Firefox: 87.0
    Safari: 14.0.3
  npmPackages:
    @ant-design/icons: ^4.5.0 => 4.5.0
    @apollo/react-hooks: ^3.1.4 => 3.1.4
    @aws-amplify/storage: ^3.1.6 => 3.1.6
    @sentry/react: ^5.27.6 => 5.27.6
    @sentry/tracing: ^5.27.6 => 5.27.6
    adm-zip: ^0.4.13 => 0.4.14
    antd: ^4.12.3 => 4.12.3
    aws-amplify: ^3.0.16 => 3.0.16
    aws-amplify-react: ^2.3.10 => 2.6.3
    aws-appsync: ^1.8.1 => 1.8.1
    aws-appsync-react: ^1.2.9 => 1.2.9
    cypress: 6.8.0 => 6.8.0
    cypress-file-upload: ^4.0.7 => 4.1.1
    cypress-plugin-tab: ^1.0.5 => 1.0.5
    docx: ^5.0.0-rc5 => 5.0.2
    docxtemplater: ^3.18.0 => 3.18.0
    downloadjs: ^1.4.7 => 1.4.7
    graphql-tag: ^2.10.1 => 2.10.3
    jszip: ^3.2.2 => 3.2.2
    pizzip: ^3.0.6 => 3.0.6
    query-string: ^6.13.8 => 6.13.8
    rc-queue-anim: ^1.8.5 => 1.8.5
    rc-scroll-anim: ^2.7.4 => 2.7.4
    react: ^17.0.1 => 17.0.1
    react-apollo: ^3.1.4 => 3.1.4
    react-beforeunload: ^2.2.1 => 2.2.1
    react-data-grid: ^6.1.0 => 6.1.0
    react-data-grid-addons: ^6.1.0 => 6.1.0
    react-document-title: ^2.0.3 => 2.0.3
    react-dom: ^16.8.6 => 16.13.1
    react-hotkeys: ^2.0.0 => 2.0.0
    react-markdown: ^4.3.1 => 4.3.1
    react-router-dom: ^5.0.1 => 5.1.2
    react-scripts: 3.0.1 => 3.0.1
    sentry-files: ^1.0.1 => 1.0.1
    smpte-timecode: ^1.2.3 => 1.2.3
    video-react: ^0.14.1 => 0.14.1
    virtualizedtableforantd: ^0.7.8 => 0.7.8
    virtualizedtableforantd4: ^1.1.2 => 1.1.2
  npmGlobalPackages:
    @aws-amplify/cli: 4.46.1
    amplify-app: 2.16.0
    n: 6.8.0
    np: 6.3.2
    npm: 6.14.9
    to: 0.2.9
    web-ext: 5.0.0

Describe the bug

I have a ReactJs App, using Amplify and for some reason, in specific moments for specific users it peaks errors refreshing the authentication token. I only know that because those exceptions are catched on Sentry, and the user has reported weird behaviour (i.e: its data not being saved)

The stack trace on Sentry leads to this:

Error: Cannot retrieve a new session. Please authenticate.
  at getSession(../../../../src116575210/src/lexis/node_modules/amazon-cognito-identity-js/es/CognitoUser.js:1299:1)
  at call(../../../../src116575210/src/lexis/node_modules/@aws-amplify/auth/lib-esm/Auth.js:1447:1)
  at step(../../../../src116575210/src/lexis/node_modules/@aws-amplify/auth/lib-esm/Auth.js:139:1)
  at next(../../../../src116575210/src/lexis/node_modules/@aws-amplify/auth/lib-esm/Auth.js:69:1)
  at R/<(../../../../src116575210/src/lexis/node_modules/@aws-amplify/auth/lib-esm/Auth.js:41:1)
  at Auth_awaiter(../../../../src116575210/src/lexis/node_modules/@aws-amplify/auth/lib-esm/Auth.js:20:1)
  at z</e.prototype.currentUserPoolUser/</<(../../../../src116575210/src/lexis/node_modules/@aws-amplify/auth/lib-esm/Auth.js:1395:16)

As you can see this the culprit code throwing the exception:

      if (!refreshToken.getToken()) {
        return callback(new Error('Cannot retrieve a new session. Please authenticate.'), null);
      }

My AppSync client setup

const client = new AWSAppSyncClient({
    url: config.aws_appsync_graphqlEndpoint,
    region: config.aws_appsync_region,
    auth: {
      type: config.aws_appsync_authenticationType,
      apiKey: config.aws_appsync_apiKey,
      jwtToken: async () => (await Auth.currentSession()).getIdToken().getJwtToken(),
    },
    disableOffline: true
});

Looking for the user interactions until this error I can see that it happens just after a GraphQL call:

ui.click
button.ant-btn.ant-btn-primary.ant-btn-lg.ant-btn-icon-only[type="button"][title="Download"]

info
12:37:50
console
Calling GraphQL Api to get docxUrl
logger: console
arguments: ["Calling GraphQL Api to get docxUrl"]

info
12:37:50
exception
Error: Cannot retrieve a new session. Please authenticate.

Just Today I got over 250 similar exceptions happening to the same user in a 5 hours time span I think it might be indication of some other issue, but I can't figure out how I can properly debug this and find out the cause.

Another thing is that I want to catch this exception on my code, but as it happens asynchronous I can't see where on my code I can catch it. I also tried to comment the check on the amplify library to always throw the exception, so I could try to catch it, but it seems that the code is never reached even waiting for a long time.

In summary, I'd like to know what is causing this issue, if you are already familiar with similar issues, or can point me to where to look, and how to catch/handle it

Thanks

Expected behavior

The token should be successfully refreshed

Reproduction steps

  • The authentication token should be refreshed
  • Then it fails to refresh
  • Throw exception "Cannot retrieve a new session. Please authenticate."

Code Snippet

// Put your code below this line.

Log output

// Put your logs below this line
Error: Cannot retrieve a new session. Please authenticate.
  at getSession(../../../../src116575210/src/lexis/node_modules/amazon-cognito-identity-js/es/CognitoUser.js:1299:1)
  at call(../../../../src116575210/src/lexis/node_modules/@aws-amplify/auth/lib-esm/Auth.js:1447:1)
  at step(../../../../src116575210/src/lexis/node_modules/@aws-amplify/auth/lib-esm/Auth.js:139:1)
  at next(../../../../src116575210/src/lexis/node_modules/@aws-amplify/auth/lib-esm/Auth.js:69:1)
  at R/<(../../../../src116575210/src/lexis/node_modules/@aws-amplify/auth/lib-esm/Auth.js:41:1)
  at Auth_awaiter(../../../../src116575210/src/lexis/node_modules/@aws-amplify/auth/lib-esm/Auth.js:20:1)
  at z</e.prototype.currentUserPoolUser/</<(../../../../src116575210/src/lexis/node_modules/@aws-amplify/auth/lib-esm/Auth.js:1395:16)

aws-exports.js

const awsmobile = {
    "aws_project_region": "us-east-1",
    "aws_cognito_identity_pool_id": "us-east-1:xxxxxx",
    "aws_cognito_region": "us-east-1",
    "aws_user_pools_id": "us-east-1_xxxxx",
    "aws_user_pools_web_client_id": "xxxxxxx",
    "oauth": {
        "domain": "xxxxx-dev.auth.us-east-1.amazoncognito.com",
        "scope": [
            "phone",
            "email",
            "openid",
            "profile",
            "aws.cognito.signin.user.admin"
        ],
        "redirectSignIn": "xxxx",
        "redirectSignOut": "xxxx",
        "responseType": "token"
    },
    "federationTarget": "COGNITO_USER_AND_IDENTITY_POOLS",
    "aws_content_delivery_bucket": "xxxx",
    "aws_content_delivery_bucket_region": "us-east-1",
    "aws_content_delivery_url": "xxxxx-dev.s3-website-us-east-1.amazonaws.com",
    "aws_user_files_s3_bucket": "xxxxxx",
    "aws_user_files_s3_bucket_region": "us-east-1",
    "aws_appsync_graphqlEndpoint": "xxxxx/graphql",
    "aws_appsync_region": "us-east-1",
    "aws_appsync_authenticationType": "AMAZON_COGNITO_USER_POOLS",
    "aws_appsync_apiKey": "xxxxx"
};

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

dcfranca avatar Apr 06 '21 18:04 dcfranca

I've just changed my AppSync client instantiation to this code, to see if I can at least catch the exceptions properly But it looks wrong, there is probably a better way to do that.

      jwtToken: async () => {
        try {
          const session = await Auth.currentSession();
          return session.getIdToken().getJwtToken();
        } catch (err) {
          errorAuthentication = 'Failed to authenticate, please sign in again';
          return '';
        }
      },

dcfranca avatar Apr 06 '21 19:04 dcfranca

Thank you for opening an issue and using the Bug Report template! I hope to be able to help you figure out a fix for this.

To start, it looks like you've got duplicate dependencies in your project. For example, if you're using aws-amplify I don't think you would need the aws-appsync library since GraphQL was added to the API category. There are known issues with using redundant/duplicate libraries. I would try to see if you can trim those aws dependencies down.

Would you mind sharing how you're configuring Amplify and make sure Amplify.configure is only called once? It could be that your AppSync client and Amplify instances are conflicting with each other.

chrisbonifacio avatar Apr 07 '21 16:04 chrisbonifacio

@chrisbonifacio Thanks for the quick reply!

This is my index.js, it is the only place where amplify.configure is called

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import './index.css';

import * as Sentry from "@sentry/react";
import { Integrations } from "@sentry/tracing";

import App from './App';
import * as serviceWorker from './serviceWorker';

import Amplify from 'aws-amplify';
import config from './aws-exports';
import AWSAppSyncClient from 'aws-appsync';
import { ApolloProvider } from '@apollo/react-hooks';
import { Auth } from 'aws-amplify';
import { getCurrentEnvironment } from './EnvironmentUtils';

const { host } = window.location;

const { version } = require('../package.json');
let errorAuthentication = null;

if (config.oauth.redirectSignIn.includes(',')) {
  const filterHost = url => new URL(url).host === host;
  config.oauth.redirectSignIn = config.oauth.redirectSignIn
    .split(',')
    .filter(filterHost)
    .shift();
  config.oauth.redirectSignOut = config.oauth.redirectSignOut
    .split(',')
    .filter(filterHost)
    .shift();
}

Amplify.configure(config);

const client = new AWSAppSyncClient({
    url: config.aws_appsync_graphqlEndpoint,
    region: config.aws_appsync_region,
    auth: {
      type: config.aws_appsync_authenticationType,
      apiKey: config.aws_appsync_apiKey,
      jwtToken: async () => {
        try {
          const session = await Auth.currentSession();
          return session.getIdToken().getJwtToken();
        } catch (err) {
          errorAuthentication = 'Failed to authenticate, please sign in again';
          return '';
        }
      },
    },
    disableOffline: true
});


Sentry.init({
  dsn: "https://xxxxxxxx.ingest.sentry.io/xxxxx",
  integrations: [
    new Integrations.BrowserTracing(),
  ],
  release: version,
  environment: getCurrentEnvironment(),
  // We recommend adjusting this value in production, or using tracesSampler
  // for finer control
  tracesSampleRate: 0.2,
});

ReactDOM.render(
    <BrowserRouter>
      <ApolloProvider client={client}>
        <App errorAuthentication={errorAuthentication} />
      </ApolloProvider>
    </BrowserRouter>,
  document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

How is the best way to share my Amplify setup?

dcfranca avatar Apr 07 '21 17:04 dcfranca

I think this may be good enough. Thank you! I see you're creating a AppSyncClient with information from the config file, which is also being used by Amplify.configure. Would you mind trying to use the API category provided by the aws-amplify library instead and see if that makes a difference?

You would have to remove the appsync client and library from your project and replace it with graphQL calls using API.graphql

Here's some documentation on using GraphQL with the API category. API (GraphQL) - Fetch data - Amplify Docs

chrisbonifacio avatar Apr 07 '21 18:04 chrisbonifacio

hmm, what you mean? Because I'm using the API category... but I'm using Apollo client instead of the Amplify one as indicated in the documentation here

dcfranca avatar Apr 08 '21 17:04 dcfranca

having the same issue when using Auth from withSSRContext

asp3 avatar Apr 08 '21 22:04 asp3

We also have the same issue. We're using Amplify with Auth and AppSync. (Without using AWSAppSyncClient, only API.graphql).

We monitor our app with Sentry, and we get this error all the time.

nimrodp avatar May 09 '21 09:05 nimrodp

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Jun 09 '21 03:06 stale[bot]

This issue has been automatically closed because of inactivity. Please open a new issue if are still encountering problems.

stale[bot] avatar Jul 21 '21 03:07 stale[bot]

This is still an issue. I've even fetched new credentials in getServerSideProps and CognitoUser.getSession is throwing the following error:

Error: Cannot retrieve a new session. Please authenticate.
    at CognitoUser.getSession (/home/username/REDACTED/node_modules/amazon-cognito-identity-js/lib/CognitoUser.js:1348:25)
    at AuthClass.<anonymous> (/home/username/REDACTED/node_modules/@aws-amplify/auth/lib/Auth.js:1125:34)
    at step (/home/username/REDACTED/node_modules/@aws-amplify/auth/lib/Auth.js:56:23)
    at Object.next (/home/username/REDACTED/node_modules/@aws-amplify/auth/lib/Auth.js:37:53)
    at /home/username/REDACTED/node_modules/@aws-amplify/auth/lib/Auth.js:31:71
    at new Promise (<anonymous>)
    at __awaiter (/home/username/REDACTED/node_modules/@aws-amplify/auth/lib/Auth.js:27:12)
    at /home/username/REDACTED/node_modules/@aws-amplify/auth/lib/Auth.js:1086:44
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (node:internal/process/task_queues:94:5)

Any ideas?

kylekirkby avatar Aug 11 '21 11:08 kylekirkby

This seems to be an issue with anonymous user access credentials retrieved from Cognito. This is a pretty major issue since how can Amplify SSR support be useful without anonymous user access???

kylekirkby avatar Aug 11 '21 11:08 kylekirkby

@dcfranca

If you are using hostedUI you should code instead of token on the responseType of your oauth config. This doesn't return refreshToken so you will have this problem.

elorzafe avatar Jul 01 '22 23:07 elorzafe

@kylekirkby @asp3 @nimrodp

I will be looking on the SSR issue and reply to this as soon as possible.

elorzafe avatar Jul 01 '22 23:07 elorzafe

@kylekirkby @asp3 @nimrodp

I will be looking on the SSR issue and reply to this as soon as possible.

It would be good to get some solid documentation in-place for this use case too :)

kylekirkby avatar Jul 04 '22 07:07 kylekirkby

@kylekirkby Is it possible that you are having multiple GraphQL request in parallel?

elorzafe avatar Jul 19 '22 18:07 elorzafe

Hi @kylekirkby following on here:

For Guest user access, it also depends on how you have access control configured on your Auth and API resources as well as on the model in your schema. For example you can use IAM for guests or API Key (although it's not recommended for production). Then based on this, you would pass authMode in to API.graphql().

An example for IAM, where I have enabled Guest users on my auth resource as well as enabled IAM as an authorization mode on my api resource:

note you can have more than one auth mode on your api resource, with a default for when authMode is not included with API.graphql()

# schema.gql
type Todo @model @auth(rules: [
  { allow: owner }, # gives full crud access to the owner
  { allow: public, operations: [read], provider: iam } # allows guest users to read Todos
]) {
  id: ID!
  name: String!
  description: String
}

// getServerSideProps()
...
const { API } = withSSRContext(context);
    try {
        const response = await API.graphql({
            query: listTodos,
            authMode: 'AWS_IAM', // set the authorization mode
        });
        return {
            props: {
                todos: response.data.listTodos.items
            }
        }
    } catch (err) {
        return {
            props: {
                err
            }   
        }
    }

With that said, I'd like to confirm your experience - is the error happening on all requests or just some as the original comment stated?

[1] https://docs.amplify.aws/cli/graphql/authorization-rules/#authorization-strategies

nadetastic avatar Feb 22 '23 19:02 nadetastic

@kylekirkby At this time, I'll go ahead and close out this issue. If you still have questions regarding this please let me know

nadetastic avatar Mar 13 '23 23:03 nadetastic