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

Calling signIn() immediately after signOut() results in access token has been revoked #9838

Closed theogravity closed 11 months ago

theogravity commented 2 years ago

Before opening, please confirm:

JavaScript Framework

React

Amplify APIs

Authentication

Amplify Categories

auth

Environment information

``` # Put output below this line System: OS: macOS 12.3.1 CPU: (16) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz Memory: 62.52 MB / 32.00 GB Shell: 5.8 - /bin/zsh Binaries: Node: 16.14.2 - ~/.nvm/versions/node/v16.14.2/bin/node Yarn: 1.22.18 - ~/.nvm/versions/node/v16.14.2/bin/yarn npm: 8.7.0 - ~/.nvm/versions/node/v16.14.2/bin/npm Browsers: Brave Browser: 100.1.37.116 Chrome: 100.0.4896.127 Firefox: 99.0.1 Safari: 15.4 npmPackages: @apollo/client/cache: undefined () @apollo/client/core: undefined () @apollo/client/errors: undefined () @apollo/client/link/batch: undefined () @apollo/client/link/batch-http: undefined () @apollo/client/link/context: undefined () @apollo/client/link/core: undefined () @apollo/client/link/error: undefined () @apollo/client/link/http: undefined () @apollo/client/link/persisted-queries: undefined () @apollo/client/link/retry: undefined () @apollo/client/link/schema: undefined () @apollo/client/link/subscriptions: undefined () @apollo/client/link/utils: undefined () @apollo/client/link/ws: undefined () @apollo/client/react: undefined () @apollo/client/react/components: undefined () @apollo/client/react/context: undefined () @apollo/client/react/hoc: undefined () @apollo/client/react/hooks: undefined () @apollo/client/react/parser: undefined () @apollo/client/react/ssr: undefined () @apollo/client/testing: undefined () @apollo/client/testing/core: undefined () @apollo/client/utilities: undefined () @apollo/client/utilities/globals: undefined () @aws-amplify/auth: ^3.4.15 => 3.4.29 @babel/core: ^7.13.14 => 7.13.14 (7.17.7, 7.17.5, 7.12.9) @babel/preset-env: ^7.13.12 => 7.13.12 (7.16.11) @babel/preset-react: ^7.13.13 => 7.13.13 (7.16.7) @babel/runtime: ^7.13.10 => 7.13.10 @datadog/browser-logs: ^3.10.1 => 3.10.1 @datadog/browser-rum: ^3.10.1 => 3.10.1 @graphql-codegen/cli: ^2.6.2 => 2.6.2 @graphql-codegen/fragment-matcher: ^2.0.1 => 2.0.1 @graphql-codegen/introspection: ^2.1.1 => 2.1.1 @graphql-codegen/typescript: ^2.4.5 => 2.4.5 @graphql-codegen/typescript-document-nodes: ^2.2.5 => 2.2.5 @graphql-codegen/typescript-graphql-files-modules: ^2.1.1 => 2.1.1 @graphql-codegen/typescript-operations: ^2.3.2 => 2.3.2 @graphql-codegen/typescript-react-apollo: 2.3.1 => 2.3.1 @monarch/graphql-api: link:../packages/graphql-api => 1.0.0 @monarch/utils: link:../packages/utils => 1.0.0 @pmmmwh/react-refresh-webpack-plugin: ^0.5.4 => 0.5.4 @radix-ui/react-context-menu: ^0.1.1 => 0.1.1 @radix-ui/react-dropdown-menu: ^0.1.1 => 0.1.1 @radix-ui/react-popover: ^0.1.1 => 0.1.1 @radix-ui/react-radio-group: 0.1.4 => 0.1.4 @rehooks/component-size: ^1.0.3 => 1.0.3 @segment/analytics-next: ^1.33.4 => 1.33.4 @simbathesailor/use-what-changed: ^2.0.0 => 2.0.0 @storybook/addon-actions: ^6.1.11 => 6.1.21 @storybook/addon-controls: ^6.1.11 => 6.1.21 @storybook/addon-essentials: ^6.1.11 => 6.1.21 @storybook/addon-links: ^6.1.11 => 6.1.21 @storybook/node-logger: ^6.1.11 => 6.1.21 (6.4.19) @storybook/react: ^6.4.19 => 6.4.19 @svgr/webpack: ^5.5.0 => 5.5.0 @testing-library/jest-dom: ^5.15.0 => 5.15.0 @testing-library/react: ^12.1.2 => 12.1.2 @testing-library/react-hooks: ^7.0.2 => 7.0.2 @testing-library/user-event: ^13.5.0 => 13.5.0 @theo.gravity/apollo-client: 3.5.10 @tippyjs/react: ^4.2.1 => 4.2.5 @twilio/conversations: ^2.1.0 => 2.1.0 @twilio/video-processors: ^1.0.1 => 1.0.1 @twilio/video-room-monitor: ^1.0.0-beta.1 => 1.0.0-beta.1 @types/chrome: 0.0.100 => 0.0.100 @types/classnames: ^2.2.10 => 2.2.11 @types/detect-browser: ^4.0.0 => 4.0.0 @types/dom-mediacapture-record: ^1.0.7 => 1.0.7 @types/dompurify: ^2.2.3 => 2.2.3 @types/extract-domain: ^2.3.0 => 2.3.0 @types/jest: ^24.0.0 => 24.9.1 (27.0.2) @types/latinize: ^0.2.15 => 0.2.15 @types/lodash: ^4.14.178 => 4.14.178 (4.14.173, 4.14.168, 4.14.177) @types/math-expression-evaluator: ^1.2.0 => 1.2.0 @types/node: ^12.0.0 => 12.20.7 (14.14.37, 14.18.12, 14.17.27) @types/object-hash: ^1.3.4 => 1.3.4 @types/p-limit: ^2.2.0 => 2.2.0 @types/pako: ^1.0.3 => 1.0.3 @types/qrcode.react: ^1.0.1 => 1.0.1 @types/react: ^16.9.0 => 16.14.5 (17.0.3, 17.0.29) @types/react-copy-to-clipboard: ^4.3.0 => 4.3.0 @types/react-dom: ^16.9.0 => 16.9.12 (17.0.9, 17.0.3) @types/react-grid-layout: ^0.17.1 => 0.17.2 @types/react-pdf: ^4.0.5 => 4.0.6 @types/react-resizable: ^1.7.2 => 1.7.2 @types/react-router-dom: ^5.1.5 => 5.1.7 @types/sat: ^0.0.31 => 0.0.31 @types/serialize-error: ^4.0.1 => 4.0.1 @types/shortid: ^0.0.29 => 0.0.29 @types/styled-components: ^5.1.0 => 5.1.9 @types/tinycolor2: ^1.4.2 => 1.4.2 @types/ua-parser-js: ^0.7.35 => 0.7.35 @types/unsplash-js: ^7.0.0 => 7.0.0 @types/url-regex-safe: ^1.0.0 => 1.0.0 @types/use-resize-observer: ^6.0.0 => 6.0.0 @types/uuid: ^8.0.0 => 8.3.0 @types/yup: ^0.29.2 => 0.29.11 @types/zen-observable: ^0.8.3 => 0.8.3 @zeit/fetch-retry: ^5.0.0 => 5.0.1 amazon-cognito-identity-js: 4.6.3 => 4.6.3 (4.6.0) apollo-link-timeout: ^4.0.0 => 4.0.0 assert: ^2.0.0 => 2.0.0 aws-amplify: ^3.3.12 => 3.3.26 aws-sdk: ^2.725.0 => 2.875.0 babel-loader: ^8.2.2 => 8.2.2 (8.2.3) babel-plugin-graphql-tag: ^3.3.0 => 3.3.0 babel-plugin-styled-components: ^1.12.0 => 1.12.0 babel-polyfill: ^6.26.0 => 6.26.0 buffer: ^6.0.3 => 6.0.3 (4.9.2, 5.7.1) classnames: ^2.2.6 => 2.2.6 (2.3.1) copy-to-clipboard: ^3.3.1 => 3.3.1 copy-webpack-plugin: ^7.0.0 => 7.0.0 css-loader: ^5.0.1 => 5.2.0 (3.6.0) date-fns: ^2.17.0 => 2.19.0 (1.30.1) detect-browser: ^5.1.1 => 5.2.0 dompurify: ^2.3.3 => 2.3.3 email-regex-safe: ^1.0.2 => 1.0.2 email-validator: ^2.0.4 => 2.0.4 escape-string-regexp: ^4.0.0 => 4.0.0 (1.0.5, 2.0.0) eslint: ^8.10.0 => 8.10.0 eventemitter3: ^4.0.4 => 4.0.7 (2.0.3, 3.1.2) extract-domain: ^2.3.3 => 2.3.3 fake-indexeddb: ^3.1.2 => 3.1.2 formik: ^2.2.9 => 2.2.9 framer-motion: ^4.1.17 => 4.1.17 graphql: ^15.8.0 => 15.8.0 (14.0.0) graphql-tag: ^2.12.6 => 2.12.6 (2.11.0) graphql-ws: ^5.6.1 => 5.6.1 heic2any: ^0.0.3 => 0.0.3 html-react-parser: ^1.4.0 => 1.4.0 html-webpack-plugin: ^4.5.0 => 4.5.2 html-webpack-tags-plugin: ^3.0.0 => 3.0.0 immer: ^9.0.7 => 9.0.7 jest: ^26.6.3 => 26.6.3 jest-mock-extended: ^2.0.4 => 2.0.4 jsmpeg-player: 3.0.1 => 3.0.1 jwt-decode: ^3.1.2 => 3.1.2 latinize: ^0.5.0 => 0.5.0 launchdarkly-react-client-sdk: ^2.25.0 => 2.25.0 levenary: ^1.1.1 => 1.1.1 lodash: ^4.17.21 => 4.17.21 loglayer: ^1.0.2 => 1.0.2 math-expression-evaluator: ^1.2.22 => 1.3.7 (1.3.8) mini-css-extract-plugin: ^1.3.3 => 1.4.0 netlify-webpack-plugin: ^1.1.3 => v1.1.3 object-hash: ^2.0.3 => 2.1.1 omit-deep: ^0.3.0 => 0.3.0 p-defer: ^3.0.0 => 3.0.0 pako: ^2.0.4 => 2.0.4 path-browserify: ^1.0.1 => 1.0.1 pdfjs-dist: 2.1.266 => 2.1.266 pkg-dir: ^5.0.0 => 5.0.0 (3.0.0, 4.2.0) prettier: ^2.0.5 => 2.2.1 (2.0.5, 2.3.0) qrcode.react: ^1.0.0 => 1.0.1 react: ^16.14.0 => 16.14.0 react-canvas-color-picker: 1.0.21 => 1.0.21 react-contenteditable: ^3.3.5 => 3.3.5 react-cool-dimensions: ^2.0.7 => 2.0.7 react-copy-to-clipboard: ^5.0.2 => 5.0.3 react-device-detect: ^1.14.0 => 1.17.0 react-dnd: ^11.1.3 => 11.1.3 react-dnd-html5-backend: ^11.1.3 => 11.1.3 react-dnd-touch-backend: ^11.1.3 => 11.1.3 react-docgen-typescript: ^1.20.5 => 1.21.0 (2.2.2) react-dom: ^16.14.0 => 16.14.0 react-hotkeys-hook: ^3.3.1 => 3.3.1 react-icons: ^3.10.0 => 3.11.0 react-merge-refs: ^1.1.0 => 1.1.0 react-pdf: ^4.1.0 => 4.2.0 react-quill: ^1.3.5 => 1.3.5 react-rating: ^2.0.5 => 2.0.5 react-refresh: ^0.11.0 => 0.11.0 react-resizable: ^1.10.1 => 1.11.1 react-router-dom: ^5.2.0 => 5.2.0 react-spring: ^9.2.4 => 9.2.4 react-typeform-embed: ^0.2.1 => 0.2.1 react-use-gesture: ^9.1.3 => 9.1.3 react-youtube: ^7.12.0 => 7.13.1 redux: ^4.0.5 => 4.0.5 reselect: ^4.1.3 => 4.1.3 roarr: ^7.7.0 => 7.7.0 sat: ^0.8.0 => 0.8.0 serialize-error: ^7.0.1 => 7.0.1 (8.0.1) slugify: ^1.5.0 => 1.5.0 source-map-explorer: ^2.4.2 => 2.5.2 speed-measure-webpack-plugin: ^1.3.3 => 1.5.0 stream-browserify: ^3.0.0 => 3.0.0 styled-components: ^5.2.1 => 5.2.1 styled-components/macro: undefined () styled-components/native: undefined () styled-components/primitives: undefined () tinycolor2: ^1.4.2 => 1.4.2 (1.4.1) tippy-react-headless: 0.1.0 ts-graphql-plugin: ^1.12.0 => 1.12.1 twilio-chat: ^4.0.0 => 4.1.0 twilio-video: ^2.21.1 => 2.21.1 typescript: ^4.5.4 => 4.5.4 typescript-styled-plugin: ^0.15.0 => 0.15.0 ua-parser-js: 0.7.26 => 0.7.26 unsplash-js: ^7.0.3 => 7.0.15 url-regex-safe: ^2.0.2 => 2.0.2 use-async-effect: ^2.2.3 => 2.2.3 use-resize-observer: ^6.1.0 => 6.1.0 util: ^0.12.3 => 0.12.3 (0.12.4) uuid: ^8.2.0 => 8.3.2 (3.4.0, 3.3.2) wait-port: ^0.2.9 => 0.2.9 webpack: ^5.28.0 => 5.28.0 webpack-bundle-analyzer: ^4.2.0 => 4.4.0 webpack-cli: ^4.2.0 => 4.6.0 webpack-dev-server: ^3.11.3 => 3.11.3 webpack-merge: ^5.7.0 => 5.7.3 worker-loader: ^3.0.8 => 3.0.8 (2.0.0) yup: ^0.32.11 => 0.32.11 zen-observable: ^0.8.15 => 0.8.15 (0.7.1) npmGlobalPackages: corepack: 0.10.0 npm: 8.7.0 yarn: 1.22.18 ```

Describe the bug

CleanShot 2022-04-26 at 15 49 02

Expected behavior

The Auth.signIn() call should succeed given correct credentials.

Reproduction steps

See bug description and code snippet.

Code Snippet

// Put your code below this line.
      const user = await Auth.currentAuthenticatedUser();

      await Auth.changePassword(user, oldPassword, newPassword);

      await Auth.signOut({ global: true });

      await Auth.signIn({
        username: user.username,
        password: newPassword,
      });

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

marla-hoggard commented 2 years ago

I'm the colleague who sees the error most of the time, so I'll add a few more details:

If I had to make a guess as to what is going on (without knowing how these methods work under the hood), it appears to me as though the global sign out method continues to search for tokens to revoke slightly past the time that the awaited promise resolves, so if the SignIn call takes place too quickly, the sign out call revokes its token too, causing the sign in to fail.

mariela-plaza commented 2 years ago

We are having the same issue in our project. The second situation marla-hoggard describes (wrapping the Auth.SingIn in a try/catch) is what we have implemented, and the SignIn process always fails the first time but succeeds the second time around.

lalit-g-deepr commented 2 years ago

I am also facing same issue.

cwomack commented 1 year ago

The developer preview for v6 of Amplify has officially been released with updates to the Auth package, error handling, and much more! Please check out our announcement and updated documentation to see what has changed.

We believe this issue should be resolved within the dev preview and upcoming General Availability for Amplify v6, but let us know with a comment if there are further issues.

cwomack commented 11 months ago

With the release of the latest major version of Amplify (aws-amplify@>6), this issue should now be resolved! Please refer to our release announcement, migration guide, and documentation for more information.

spaguette commented 7 months ago

Hello team, It seems that the issue is still there, although not reproducible 100% of the times, there's is a reasonably consistent pattern how I was able to reproduce it (aws-amplify version 6.0.18). Also reproducible if I use the globalSignOut from the amazon-cognito-identity-js version 6.3.7 instead.

I'm trying to implement the case for ensuring that the User session can only be used once across devices. Without waiting for some seconds between the global sign out and the last sign in, the newest token issued by the last sign in will be revoked :(

The code for my "signInSingleSession" function:

const out = await signIn({ username, password });
  if (!out.isSignedIn) {
    return out;
  }

  await signOut({ global: true });

 // await new Promise((resolve) => setTimeout(resolve, 5000)); // if I add smth like this, the issue seems to be gone.

  await signIn({ username, password });

My FE also checks every second if the tokens are valid, otherwise redirects to the sign in page:

// in a React component:
  const goToLoginPage = useCallback(() => navigate("/sign-in"), [navigate]);

  useEffect(() => {
    void validateSingletonSession({ onFailure: goToLoginPage });
    const intervalId = window.setInterval(
      () => validateSingletonSession({ onFailure: goToLoginPage }),
      60000,
    );

    return () => window.clearInterval(intervalId);
  }, [goToLoginPage]);

 // in authService:
 export async function validateSingletonSession({
  onFailure,
}: {
  onFailure: () => void;
}) {
  try {
    // Doesn't matter what we fetch here. We just need to trigger a request to Cognito that validates the token,
    // but does not refresh it.
    await fetchUserAttributes(); // this already tries to fetch auth token inside (without force refresh)
  } catch (error) {
    // To clear the current session, and to make sure that the token is indeed revoked,
    // we need to try to force-refresh the token.
    const { tokens } = await fetchAuthSession({ forceRefresh: true });
    if (!tokens) {
      console.error("Failed to get the current user!", error);
      onFailure();
    }
  }
}

How I was able to reproduce:

  1. Log in in Chrome (latest)
  2. Log in in Safari (latest)
  3. Wait for 1 minute
  4. Chrome redirects to the sign in page
  5. Try to log in again in Chrome
  6. The second sign in (the one after the global sign out) correctly issues a new refresh token, but it's still revoked 🤔

It seems that the issue might be in the underlying library (Cognito provider?), but is there a way to actually reliably wait for the tokens to be revoked without trying to guess the duration?

havilezsoto commented 5 months ago

I would assume this is still an open issue? Why is it closed?