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

oauth/token endpoint called twice #4729

Closed constantin-melniciuc closed 4 years ago

constantin-melniciuc commented 4 years ago

Describe the bug I'm trying to do a federated authentication. I do understand the process of how a federated sign in works. It all works for me until the last moment. After I do manage to signup/sign-in with my social identity (Facebook/Google) I'm stuck with a double call from the aws-amplify js-sdk to the ${domain}/ouath2/token endpoint. One results successfuly returning the idToken, accessToken and refreshToken, the second one resulting in invalid_grant, I believe do the fact I'm requesting 2 tokens almost instantly and that being a security feature, gives me a broken state.

I also tried running different versions of the SDK, 2.1.0, unstable, 2.2.0, 1.3.3, but the behaviour didn't change.

To Reproduce Steps to reproduce the behavior:

  1. Setup any React App environment
  2. Setup an onclick event on a button as () => Auth.federatedSignIn({ provider: 'Facebook' })
  3. Check the the Network tab
  4. See once successfull request and one failing.

Screenshots see double requests image

first request was successfull: image

start time: image

Second request failed: image

Start time image

console with errors image

React APP, based on CRA ``` System: OS: Linux 4.4 Ubuntu 18.04.3 LTS (Bionic Beaver) CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz Memory: 18.84 GB / 31.73 GB Container: Yes Shell: 4.4.20 - /bin/bash Binaries: Node: 12.13.0 - ~/.nvm/versions/node/v12.13.0/bin/node Yarn: 1.19.1 - /usr/bin/yarn npm: 6.13.0 - ~/.nvm/versions/node/v12.13.0/bin/npm npmPackages: @babel/plugin-proposal-class-properties: ^7.7.4 => 7.7.4 @babel/plugin-syntax-dynamic-import: ^7.7.4 => 7.7.4 @babel/preset-react: ^7.0.0 => 7.7.4 @google/markerclusterer: ^2.0.4 => 2.0.6 @loadable/component: ^5.10.1 => 5.11.0 @sentry/browser: ^5.10.2 => 5.10.2 aws-amplify: ^2.2.2 => 2.2.2 babel-eslint: ^10.0.3 => 10.0.3 babel-plugin-transform-dynamic-import: ^2.1.0 => 2.1.0 babel-preset-env: ^1.7.0 => 1.7.0 babel-register: ^6.26.0 => 6.26.0 body-parser: ^1.18.2 => 1.19.0 classnames: ^2.2.5 => 2.2.6 core-js: ^3.4.8 => 3.6.2 create-react-server: ^0.3.2 => 0.3.2 enzyme: ^3.3.0 => 3.10.0 enzyme-adapter-react-16: ^1.1.1 => 1.15.1 enzyme-to-json: ^3.3.4 => 3.4.3 es6-promise: ^4.2.4 => 4.2.8 eslint-config-airbnb: ^18.0.1 => 18.0.1 eslint-plugin-import: ^2.19.1 => 2.19.1 eslint-plugin-jsx-a11y: ^6.2.3 => 6.2.3 eslint-plugin-react: ^7.17.0 => 7.17.0 husky: ^3.1.0 => 3.1.0 iban: 0.0.12 => 0.0.12 ibantools: ^2.0.0 => 2.2.0 jest-enzyme: ^7.1.2 => 7.1.2 jest-fetch-mock: ^2.1.2 => 2.1.2 libphonenumber-js: ^1.1.11 => 1.7.29 lint-staged: ^9.5.0 => 9.5.0 loadable-components: ^2.2.3 => 2.2.3 lodash: ^4.17.11 => 4.17.15 mgr-pdf-viewer-react: ^1.0.3 => 1.0.3 mkdirp: ^0.5.1 => 0.5.1 moment: ^2.24.0 => 2.24.0 morgan: ^1.9.0 => 1.9.1 node-sass: ^4.13.0 => 4.13.0 node-sass-chokidar: ^1.4.0 => 1.4.0 normalize.css: ^8.0.0 => 8.0.1 npm-run-all: ^4.1.2 => 4.1.5 prettier: ^1.19.1 => 1.19.1 prop-types: ^15.7.2 => 15.7.2 raf: ^3.4.0 => 3.4.1 react: ^16.8.6 => 16.12.0 react-animate-on-change: ^2.1.1 => 2.2.0 react-animated-number: ^0.4.4 => 0.4.4 react-app-rewired: ^2.1.5 => 2.1.5 react-collapsible: ^2.2.0 => 2.6.2 react-countdown-now: ^2.1.2 => 2.1.2 react-countup: ^4.2.5 => 4.3.2 react-day-picker: ^7.1.10 => 7.4.0 react-dom: ^16.8.6 => 16.12.0 react-helmet-async: 1.0.4 => 1.0.4 react-inlinesvg: ^1.2.0 => 1.2.0 react-lazyload: ^2.3.0 => 2.6.5 react-loadable: ^5.4.0 => 5.5.0 react-mobile-datepicker: ^4.0.1 => 4.0.2 react-modal: ^3.4.4 => 3.11.1 react-player: ^1.8.0 => 1.14.2 react-prerendered-component: ^1.2.2 => 1.2.4 react-redux: ^7.1.0 => 7.1.3 react-router-config: ^5.1.1 => 5.1.1 react-router-dom: ^5.1.2 => 5.1.2 react-router-redux: ^4.0.8 => 4.0.8 react-scripts: 3.3.0 => 3.3.0 react-scroll: ^1.7.10 => 1.7.14 react-share: ^3.0.1 => 3.0.1 react-signature-pad-wrapper: ^1.2.6 => 1.2.7 react-slick: 0.25.2 => 0.25.2 react-snap: 1.23.0 => 1.23.0 react-test-renderer: ^16.12.0 => 16.12.0 react-tooltip: ^3.6.0 => 3.11.1 react-transition-group: ^4.3.0 => 4.3.0 react-youtube: ^7.6.0 => 7.9.0 recharts: ^2.0.0-beta.1 => 2.0.0-beta.1 redux: ^4.0.4 => 4.0.5 redux-devtools: ^3.4.1 => 3.5.0 redux-devtools-extension: ^2.13.2 => 2.13.8 redux-form: ^8.2.6 => 8.2.6 redux-logger: ^3.0.6 => 3.0.6 redux-mock-store: ^1.5.3 => 1.5.3 redux-sentry-middleware: ^0.1.3 => 0.1.3 redux-thunk: ^2.2.0 => 2.3.0 replace-in-file: ^4.2.0 => 4.3.1 rimraf: ^3.0.0 => 3.0.0 sass-lint: ^1.12.1 => 1.13.1 sass-lint-fix: ^1.12.1 => 1.12.1 ui-kit: git+https://gitlab.com/repo/ui-kit.git => 0.6.0 urlsafe-base64: ^1.0.0 => 1.0.0 webpack-dev-middleware: ^3.7.2 => 3.7.2 workbox-webpack-plugin: ^4.3.1 => 4.3.1 npmGlobalPackages: express-generator: 4.16.1 now: 16.4.0 npm: 6.13.0 ```
aws-exports.js ```javascript import Amplify, { Auth } from 'aws-amplify'; const CURRENT_URL = `${window.location.protocol}//${window.location.host}`; Amplify.configure({ Auth: { // REQUIRED only for Federated Authentication - Amazon Cognito Identity Pool ID // identityPoolId: 'XX-XXXX-X:XXXXXXXX-XXXX-1234-abcd-1234567890ab', // REQUIRED - Amazon Cognito Region region: process.env.REACT_APP_AWS_REGION, // OPTIONAL - Amazon Cognito Federated Identity Pool Region // Required only if it's different from Amazon Cognito Region // identityPoolRegion: 'XX-XXXX-X', // OPTIONAL - Amazon Cognito User Pool ID userPoolId: process.env.REACT_APP_AWS_USER_POOL_ID, // OPTIONAL - Amazon Cognito Web Client ID (26-char alphanumeric string) userPoolWebClientId: process.env.REACT_APP_AWS_CLIENT_ID, // OPTIONAL - Enforce user authentication prior to accessing AWS resources or not mandatorySignIn: false, // OPTIONAL - Configuration for cookie storage // Note: if the secure flag is set to true, then the cookie transmission requires a secure protocol // cookieStorage: { // // REQUIRED - Cookie domain (only required if cookieStorage is provided) // domain: '', // // OPTIONAL - Cookie path // path: '/', // // OPTIONAL - Cookie expiration in days // expires: 365, // // OPTIONAL - Cookie secure flag // // Either true or false, indicating if the cookie transmission requires a secure protocol (https). // secure: isProd, // }, oauth: { domain: process.env.REACT_APP_AWS_POOL_DOMAIN, scope: ['email', 'profile'], redirectSignIn: `${CURRENT_URL}/user/my-account/preferences`, redirectSignOut: `${CURRENT_URL}/user-account/login`, responseType: 'code', }, // OPTIONAL - customized storage object // storage: new MyStorage(), // OPTIONAL - Manually set the authentication flow type. Default is 'USER_SRP_AUTH' authenticationFlowType: 'USER_PASSWORD_AUTH', }, }); // You can get the current config object const currentConfig = Auth.configure(); export default currentConfig; ```
Auth Functionality Component ```javascript import { Auth } from 'aws-amplify'; const facebookLogin = () => Auth.federatedSignIn({ provider: 'Facebook' }); class AuthPage extends PureComponent { constructor(props) { super(props); console.warn('auth page constructor'); this.state = { authState: 'signIn', authError: null, authData: null, }; Hub.listen('auth', data => { console.warn('auth-state-change', data.payload.event); switch (data.payload.event) { case 'signIn': // this.setState({ authState: 'signedIn', authData: data.payload.data }); this.props.authenticateUser(data.payload.data.signInUserSession, true); break; case 'signIn_failure': // this.setState({ authState: 'signIn', authData: null, authError: data.payload.data }); break; default: break; } }); } clicked = false; handleFB = () => { console.log('clicking fb'); // checking here if the button was clicked twice on accident. if (!this.clicked) { facebookLogin(); this.clicked = true; } } render() { return (
{this.props.children}
); } } AuthPage.propTypes = { children: node, extraClass: string, isLoggedIn: bool, ...historyPropTypes, }; const mapStateToProps = state => ({ isLoggedIn: state.layout.isLoggedIn, }); const mapDispatchToProps = dispatch => ({ authenticateUser: (user, saveToStorage) => dispatch(didAuthenticate(user, saveToStorage)), }); export default connect(mapStateToProps, mapDispatchToProps)(withRouter(AuthPage)); ```
leosoaivan commented 4 years ago

@JoraCardan I had a similar issue, where we created an Amplify micro-service authentication script to authenticate users, which lived on top of our Amplify project. In our initial setup, we ended up configuring Amplify multiple times, which caused 3 calls to the OAuth endpoints.

I don't think our setup is common at all, but just double-check Amplify isn't being configured elsewhere?

constantin-melniciuc commented 4 years ago

@JoraCardan I had a similar issue, where we created an Amplify micro-service authentication script to authenticate users, which lived on top of our Amplify project. In our initial setup, we ended up configuring Amplify multiple times, which caused 3 calls to the OAuth endpoints.

I don't think our setup is common at all, but just double-check Amplify isn't being configured elsewhere?

OMFG YOU"RE A FU**ING GENIOUS! I had exactly the same problem, I love you! Thank you so much!!!

menkari commented 3 years ago

@constantin-melniciuc @leosoaivan I'm running into the same issue with what I would consider a relatively straightforward setup. If I call Auth.config(awsconfig) on its own I don't have any issues with double calls to oauth/token and invalid_grant Its only when I call Amplify.configure(awsconfig) that I have the problem. My issue occurs when publishing to Android

Can either of you give any additional detail on how you tracked down the offending amplify.configure calls? Thanks

cdnicoll commented 3 years ago

Hey @menkari I too ran into this issue yesterday. I resolved it by updating my npm package for aws-amplify. I'm now running

"aws-amplify": "^3.3.25",

I really hope this helps. It was an annoying issue

constantin-melniciuc commented 3 years ago

@constantin-melniciuc @leosoaivan I'm running into the same issue with what I would consider a relatively straightforward setup. If I call Auth.config(awsconfig) on its own I don't have any issues with double calls to oauth/token and invalid_grant Its only when I call Amplify.configure(awsconfig) that I have the problem. My issue occurs when publishing to Android

Can either of you give any additional detail on how you tracked down the offending amplify.configure calls? Thanks

I can't remember it was over a year ago and over 6 projects ago, but I remember I had 2 places where the configuration was initialized, make sure that you have 1 single place. Or make sure the thing you're calling is not re-rendered/re-initialized, nothing more that I could suggest you here.

jlapier commented 2 years ago

I see the same behavior, posting here in the hopes it helps someone else out. My config has both Auth and API in it, and I think Amplify is double-parsing these, which has the same effect as configuring twice (and thus seeing the errant behavior where the token request happens twice). My work around was to configure them each individually.

Originally, I had this in my index:

console.log("amplify configure:")
Amplify.configure(AWS_AUTH_CONFIG);
console.log("end amplify configure")

And saw:

amplify configure:
ConsoleLogger.ts:125 [DEBUG] 09:56.493 Amplify - amplify config {Auth: {…}, API: {…}}
ConsoleLogger.ts:115 [DEBUG] 09:56.493 I18n - configure I18n
ConsoleLogger.ts:115 [DEBUG] 09:56.493 I18n - create I18n instance
ConsoleLogger.ts:115 [DEBUG] 09:56.493 AuthClass - configure Auth
ConsoleLogger.ts:125 [DEBUG] 09:56.493 Parser - parse config (3) [{…}, 'to amplifyconfig', {…}]
ConsoleLogger.ts:125 [DEBUG] 09:56.494 Hub - Dispatching to auth with  {event: 'parsingCallbackUrl', data: {…}, message: 'The callback url is being parsed'}
ConsoleLogger.ts:125 [DEBUG] 09:56.494 Hub - Dispatching to auth with  {event: 'parsingCallbackUrl', data: {…}, message: 'The callback url is being parsed'}
ConsoleLogger.ts:125 [DEBUG] 09:56.496 Hub - Dispatching to auth with  {event: 'configured', data: null, message: 'The Auth category has been configured successfully'}
ConsoleLogger.ts:125 [DEBUG] 09:56.496 Hub - Dispatching to auth with  {event: 'configured', data: null, message: 'The Auth category has been configured successfully'}
ConsoleLogger.ts:125 [DEBUG] 09:56.496 RestAPI - configure Rest API {opt: {…}}
ConsoleLogger.ts:115 [DEBUG] 09:56.496 RestAPI - create Rest API instance
ConsoleLogger.ts:125 [DEBUG] 09:56.496 RestClient - API Options {endpoints: Array(2), Auth: {…}}
ConsoleLogger.ts:125 [DEBUG] 09:56.496 PubSub - configure PubSub {opt: {…}}
ConsoleLogger.ts:125 [DEBUG] 09:56.496 GraphQLAPI - configure GraphQL API {opt: {…}}
ConsoleLogger.ts:115 [DEBUG] 09:56.497 GraphQLAPI - create Rest instance
ConsoleLogger.ts:125 [DEBUG] 09:56.497 RestClient - API Options {Auth: {…}, endpoints: Array(2)}
ConsoleLogger.ts:125 [DEBUG] 09:56.497 RestAPI - configure Rest API {opt: {…}}
ConsoleLogger.ts:115 [DEBUG] 09:56.497 RestAPI - create Rest API instance
ConsoleLogger.ts:125 [DEBUG] 09:56.497 RestClient - API Options {endpoints: Array(2), Auth: {…}}
ConsoleLogger.ts:125 [DEBUG] 09:56.498 GraphQLAPI - configure GraphQL API {opt: {…}}
ConsoleLogger.ts:115 [DEBUG] 09:56.498 GraphQLAPI - create Rest instance
ConsoleLogger.ts:125 [DEBUG] 09:56.498 RestClient - API Options {Auth: {…}, endpoints: Array(2)}
ConsoleLogger.ts:115 [DEBUG] 09:56.498 AuthClass - configure Auth
ConsoleLogger.ts:125 [DEBUG] 09:56.498 Parser - parse config (3) [{…}, 'to amplifyconfig', {…}]
ConsoleLogger.ts:125 [DEBUG] 09:56.499 Hub - Dispatching to auth with  {event: 'parsingCallbackUrl', data: {…}, message: 'The callback url is being parsed'}
ConsoleLogger.ts:125 [DEBUG] 09:56.499 Hub - Dispatching to auth with  {event: 'parsingCallbackUrl', data: {…}, message: 'The callback url is being parsed'}
ConsoleLogger.ts:125 [DEBUG] 09:56.499 Hub - Dispatching to auth with  {event: 'configured', data: null, message: 'The Auth category has been configured successfully'}
ConsoleLogger.ts:125 [DEBUG] 09:56.500 Hub - Dispatching to auth with  {event: 'configured', data: null, message: 'The Auth category has been configured successfully'}
index.tsx:33 end amplify configure

Versus using this:

console.log("amplify configure:")
Auth.configure(AWS_AUTH_CONFIG)
API.configure(AWS_AUTH_CONFIG)
console.log("end amplify configure")

and then seeing:

amplify configure:
ConsoleLogger.ts:115 [DEBUG] 09:05.355 AuthClass - configure Auth
ConsoleLogger.ts:125 [DEBUG] 09:05.355 Parser - parse config (3) [{…}, 'to amplifyconfig', {…}]
ConsoleLogger.ts:125 [DEBUG] 09:05.356 Hub - Dispatching to auth with  {event: 'parsingCallbackUrl', data: {…}, message: 'The callback url is being parsed'}
ConsoleLogger.ts:125 [DEBUG] 09:05.356 Hub - Dispatching to auth with  {event: 'parsingCallbackUrl', data: {…}, message: 'The callback url is being parsed'}
ConsoleLogger.ts:125 [DEBUG] 09:05.357 Hub - Dispatching to auth with  {event: 'configured', data: null, message: 'The Auth category has been configured successfully'}
ConsoleLogger.ts:125 [DEBUG] 09:05.357 Hub - Dispatching to auth with  {event: 'configured', data: null, message: 'The Auth category has been configured successfully'}
ConsoleLogger.ts:125 [DEBUG] 09:05.357 RestAPI - configure Rest API {opt: {…}}
ConsoleLogger.ts:115 [DEBUG] 09:05.357 RestAPI - create Rest API instance
ConsoleLogger.ts:125 [DEBUG] 09:05.357 RestClient - API Options {endpoints: Array(2), Auth: {…}}
ConsoleLogger.ts:125 [DEBUG] 09:05.357 GraphQLAPI - configure GraphQL API {opt: {…}}
ConsoleLogger.ts:115 [DEBUG] 09:05.357 GraphQLAPI - create Rest instance
ConsoleLogger.ts:125 [DEBUG] 09:05.357 RestClient - API Options {Auth: {…}, endpoints: Array(2)}
index.tsx:33 end amplify configure
github-actions[bot] commented 1 year 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.