title: MERN OAuth Implementation does not redirect to the google login page
body: <p>I'm currently running a webserver using the MERN stack, and I'm trying to get OAuth login working properly. However, when I click the "login with google" button, react loads the homepage (but the URL changes). Fetching the URL directly gets a 302 response from the server, but my front-end doesn't change. </p>
  
  <p>Server.js</p>
  
  <pre><code>const express = require('express');
  const path = require('path');
  const mongoose = require('mongoose');
  const bodyParser = require('body-parser');
  const logger = require('morgan');
  const cors = require('cors');
  const secure = require('express-force-https');
  const passport = require('passport');
  const cookieSession = require('cookie-session');
  
  require('dotenv').config();
  
  const app = express();
  const port = process.env.PORT || 5000;
  const dbRoute = process.env.MONGODB_URI || 'NO DB ROUTE PROVIDED';
  
  // db setup
  mongoose.connect(
    dbRoute,
    {
      useNewUrlParser: true,
      useUnifiedTopology: true,
      dbName: process.env.DATABASE_NAME,
    }
  );
  
  let db = mongoose.connection;
  db.once('open', () =&gt; console.log("Connected to the database"));
  db.on('error', console.error.bind(console, "MongoDB connection error: "));
  
  // middleware
  app.use(cors());
  app.use(bodyParser.urlencoded({ extended: false })); // body parsing
  app.use(bodyParser.json());
  app.use(logger("dev"));
  app.use(express.static(path.join(__dirname, "client", "build"))); // for serving up the clientside code
  app.use(secure); // ensure that the connection is using https
  app.use(cookieSession({ // cookies!
    maxAge: 30 * 24 * 60 * 60 * 1000, // 30 days
    keys:['vcxzkjvasddkvaosd'] // yeah i'm sure that's secure enough
  }));
  
  // models
  require('./models/rule');
  require('./models/affix');
  require('./models/user');
  
  // passport security
  require('./config/passport');
  app.use(passport.initialize());
  app.use(passport.session());
  
  // routes
  app.use(require('./routes'));
  
  // The "catchall" handler: for any request that doesn't
  // match one above, send back React's index.html file.
  app.get('*', (req, res) =&gt; {
    res.sendFile(path.join(__dirname+'/client/build/index.html'));
  });
  
  app.listen(port);
  
  console.log(`Server listening on ${port}`);
  </code></pre>
  
  <p>Route (There are a few index files in different folders, so the full path for this route it <code>/api/user/google</code>)</p>
  
  <pre><code>const mongoose = require('mongoose');
  const passport = require('passport');
  const router = require('express').Router();
  const auth = require('../auth');
  const User = mongoose.model('User');
  
  router.get('/google', 
    passport.authenticate('google', {
      scope: ['profile', 'email']
    })
  );
  
  router.get('/google/callback', 
    passport.authenticate('google', { failureRedirect: '/affixes'}),
    (req, res) =&gt; {
      res.redirect('/?token=' + req.user.token);
    }
  );
  </code></pre>
  
  <p>Passport.js</p>
  
  <pre><code>const mongoose = require('mongoose');
  const passport = require('passport');
  const GoogleStrategy = require('passport-google-oauth20').Strategy;
  require('dotenv').config();
  
  const User = mongoose.model('User');
  
  passport.serializeUser(function(user, done) {
    done(null, user.id);
  });
  
  passport.deserializeUser(function(id, done) {
    User.findById(id).then((user) =&gt; {
      done(null, user);
    })
  });
  
  passport.use(new GoogleStrategy({
      clientID: process.env.OAUTH_CLIENT_ID,
      clientSecret: process.env.OAUTH_CLIENT_SECRET,
      callbackURL: '/api/user/google/callback',
      proxy: true
    },
  
    (accessToken, refreshToken, profile, done) =&gt; {
      User.findOne({ googleId: profile.id })
        .then((existingUser) =&gt; {
          if (existingUser) {
            done(null, existingUser);
          } else {
            new User({ googleId: profile.id }).save()
              .then((user) =&gt; done(null, user));
          }
        });
    }
  ));
  </code></pre>
  
  <p>Frontend login page (has a fetch button and a link button. As described above, different behavior)</p>
  
  <pre><code>import React from 'react';
  import {
    ComingSoon
  } from '../Common';
  import {
    Button
  } from '@material-ui/core';
  
  const handleClick = () =&gt; {
    fetch('/api/user/google')
  }
  
  export default function Login() {
    return (
      &lt;&gt;
        &lt;Button onClick={handleClick}&gt;
          Login with Google
        &lt;/Button&gt;
  
        &lt;a href="/api/user/google"&gt;&lt;button&gt;Log in with Google&lt;/button&gt;&lt;/a&gt;
      &lt;/&gt;
    );
  }
  </code></pre>
  
  <p>Update: Looks like some kind of CORS issue, although I still don't know how to fix it. Browser spits out </p>
  
  <pre><code>Access to fetch at '...' (redirected from 'http://localhost:3000/api/user/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 an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
  </code></pre>
  
  <p>Adding the requested header gives me </p>
  
  <pre><code>Access to fetch at '...' (redirected from 'http://localhost:3000/api/user/google') from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
  </code></pre>