简体   繁体   中英

Facing CORS error even after adding CORS options on React/Node/Passport for Google Authentication

I am building a simple app with React as frontend and Node/Express/MongoDB as backend. I am authenticating user using Passport. Local authentication is working, as well as Google authentication.

I just seem to not able to load the google login page through the app. I am getting CORS error. I have shared the error below.

On React Login page:


const onClick = async () => {
    await Axios.get('/auth/google');
  };

Proxy Middleware:

const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function (app) {
  app.use(createProxyMiddleware('/auth', { target: 'http://localhost:4000' }));
};

Node Server.js: app.use('/auth', require('./routes/auth'));

routes/auth file:

const cors = require('cors');

var corsOptions = {
  origin: 'http://localhost:3000',
  methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
  preflightContinue: false,
  optionsSuccessStatus: 204,
};

router.get(
  '/google',
  cors(corsOptions),
  passport.authenticate('google', {
    scope: ['profile', 'email'],
  }),
);

router.get('/google/redirect',cors(corsOptions), passport.authenticate('google'), (req, res) => {
  res.send(req.user);
});

passportconfig.js:

passport.use(
    new GoogleStrategy(
      {
        clientID: ClientID,
        clientSecret: ClientSecret,
        callbackURL: '/auth/google/redirect',
        proxy: true,
      },
      (accessToken, refreshToken, profile, done) => {
        // passport callback function
        //check if user already exists in our db with the given profile ID
        User.findOne({ googleId: profile.id }).then((currentUser) => {
          if (currentUser) {
            //if we already have a record with the given profile ID
            done(null, currentUser);
          } else {
            //if not, create a new user
            new User({
              googleId: profile.id,
            })
              .save()
              .then((newUser) => {
                done(null, newUser);
              });
          }
        });
      },
    ),
  );

Error:

Access to XMLHttpRequest at 'https://accounts.google.com/o/oauth2/v2/auth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauth%2Fgoogle%2Fredirect&scope=profile%20email&client_id=<clientID>.apps.googleusercontent.com' (redirected from 'http://localhost:3000/auth/google') from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

If I click on the above XMLHttpRequest link, I am able to authenticate and an account is created on my DB with googleID.

I have tried different options suggested throughout inte.net, but none of them is working for me. I am not sure what is going wrong here.

According to the documentation , try removing the corsOptions entirely and just use the cors() function in your express middle-ware before any router is declared. Like so:

app.use(cors());

Let me know if this works.

// step 1:
// onClick handler function of the button should use window.open instead 
// of axios or fetch
const loginHandler = () => window.open("http://[server:port]/auth/google", "_self")

//step 2: 
// on the server's redirect route add this successRedirect object with correct url. 
// Remember! it's your clients root url!!! 
router.get(
    '/google/redirect', 
    passport.authenticate('google',{
        successRedirect: "[your CLIENT root url/ example: http://localhost:3000]"
    })
)

// step 3:
// create a new server route that will send back the user info when called after the authentication 
// is completed. you can use a custom authenticate middleware to make sure that user has indeed 
// been authenticated
router.get('/getUser',authenticated, (req, res)=> res.send(req.user))

// here is an example of a custom authenticate express middleware 
const authenticated = (req,res,next)=>{
    const customError = new Error('you are not logged in');
    customError.statusCode = 401;
    (!req.user) ? next(customError) : next()
}
// step 4: 
// on your client's app.js component make the axios or fetch call to get the user from the 
// route that you have just created. This bit could be done many different ways... your call.
const [user, setUser] = useState()
useEffect(() => {
    axios.get('http://[server:port]/getUser',{withCredentials : true})
    .then(response => response.data && setUser(response.data) )
},[])


will load your servers auth url on your browser and make the auth request.将在您的浏览器上加载您的服务器身份验证 url 并发出身份验证请求。
then reload the client url on the browser when the authentication is complete.然后在身份验证完成后在浏览器上重新加载客户端url。
makes an api endpoint available to collect user info to update the react state使 api 端点可用于收集用户信息以更新反应 state
makes a call to the endpoint, fetches data and updates the users state.用端点,获取数据并更新用户 state。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM