Why fetching a server API which triggers Oauth2 Google authentication results in `No 'Access-Control-Allow-Origin'` error?

倾然丶 夕夏残阳落幕 提交于 2019-12-25 04:02:45

问题


I want to authenticate a user using Google's Oauth2 mechanism. I have a React component with a button. The button's click handler makes an AJAX request to my server:

import React from 'react';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import PropTypes from 'prop-types';
import Button from '@material-ui/core/es/Button/Button';
import LinearProgress from '@material-ui/core/es/LinearProgress/LinearProgress';
import constants from '../../constants.js';
import { setGoogleAuthStatus, setLoggedInStatus } from '../../actions/appActions.js';

class Login extends React.Component {
  handleSignIn = () => {
    const { setLoggedInStatus } = this.props;

    fetch('http://localhost:3000/auth/login', {
      method: "GET"
    }).then(response => {
      console.log(`response=${response.text()}`);
      if (response.ok) {
        setLoggedInStatus(true);
      }
    }).catch(e => console.log(e));
  }

  render() {
    return (
      <div>
        <Button variant="contained" component="span"
        onClick={this.handleSignIn}>
          Sign in with Google
        </Button>
      </div>
    );
  }
}

Login.propTypes = {
  googleInit: PropTypes.bool.isRequired
};

const mapStateToProps = state => {
  return {
    googleInit: state.auth.googleInit
  };
};

const LoginConnected = connect(mapStateToProps,
  { setGoogleAuthStatus, setLoggedInStatus })(Login);
export default withRouter(LoginConnected);

In my server which is running at http://localhost:3000 and using Express.js I have middleware on all routes which handles CORS:

const allowCORS = (req, res, next) => {
  console.log('req.headers.origin = ' + req.headers.origin);
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
  res.header('Access-Control-Allow-Headers', 'Content-Type');

  next();
};

This is the function which handles the route http://localhost:3000/auth/login:

const passportAuth = (req, res, next) => {
  console.log('from passportAuth');
  // Start OAuth 2 flow using Passport.js
  passport.authenticate('google', { scope: ['email', 'profile'] })(req, res, next);
};

This is router which handles Google callback URL route:

router.get('http://localhost:3000/auth/google/callback',
    passport.authenticate('google'), (req, res) => {
res.status(httpStatusCodes.OK).redirect('http://localhost:3005/home');
    });

Also I made sure to enable the domains in Google dashboard:

The problem is when I click the Google sign in button I get this error:

I don't know what why CORS is a problem since I enabled domains from any origin in my server. From debug I see that the server route responsible for http://localhost:3000/auth/login is called but Passport.js authenticate method isn't called. In addition I know that my server authentication works if I enter http://localhost:3000/auth/login in the browser address. But it doesn't work from my website. What could be my problem?

My browser is Chrome.


EDIT: I think I've found my problem: the function which handles the route http://localhost:3000/auth/login has this code:

const passportAuth = (req, res, next) => {
  console.log('from passportAuth');
  // Start OAuth 2 flow using Passport.js
  passport.authenticate('google', { scope: ['email', 'profile'] })(req, res, next);
};

Because my frontend runs at http://localhost:3005 and AJAX request from frontend is made to http://localhost:3000/auth/login CORS is invoked. In the server when I get the request to the route http://localhost:3000/auth/login I call passport.authenticate('google', { scope: ['email', 'profile'] })(req, res, next); but I don't respond to the original request, therefore, CORS header is not set hence Chrome error. The problem is calling response.send() after passport.authenticate doesn't work. Also I don't see how I can respond to the request from inside passport.js. Is there a way to respond with response.send() first and then call passport.authenticate?

来源:https://stackoverflow.com/questions/55081056/why-fetching-a-server-api-which-triggers-oauth2-google-authentication-results-in

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!