I am having the same issue as issue CORs Error: Google Oauth from React to Express (PassportJs validation). But I am unable to get the solution offered by @Yazmin to work.
I am attempting to create a React, Express/Nodejs, MongoDB stack with Google authentication and authorization. I am currently developing the stack on Windows 10, using Vs Code (React on ‘localhost:3000, Nodejs on localhost:5000 and MongoDB on localhost:27017.
The app’s purpose is to display Urban Sketches(images) on a map using google maps, google photos api and google Gmail api. I may in the future also require similar access to Facebook Groups to access Urban Sketches. But for now I have only included the profile and Email scopes for authorization.
I want to keep all requests for third party resources in the backend, as architecturally I understand this is best practice.
The google authorization process from origin http://localhost:5000 works just fine and returns the expected results. However, when I attempt to do the same from the client - origin Http://localhost:3000 the following error is returned in the developers tools console following the first attempt to access the google auth2 api. Although the scheme and domain are the same the port is different, so the message from the third part (Https://account.google.com) has been rejected by the browser.
Access to fetch at 'https://accounts.google.com/o/oauth2/v2/auth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2Fauth%2Fgoogle%2Fcallback&scope=profile%20email%20https%3A%2F%2Fmail.google.com%2F&client_id=' (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 an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
No matter what I try the error message is the same.
I think that google is sending the reply to the client (localhost:3000) rather than to the server.
Among other solutions, I attempted to implement Yilmaz’s solution by Quote: “Create setupProxy.js file in client/src. No need to import this anywhere. create-react-app will look for this directory” I had already created my client by running create-react-app previously. So I added setupProxy.js inside my src folder.
Question: I assume I am correct that the new setupProxy.cjs file containing my settings will be included by webpack after I restart the client.
It seems to me that the flow I am getting is not BROWSER ==> EXPRESS ==> GOOGLE-SERVER but BROWSER ==> EXPRESS ==> GOOGLE-SERVER ==>BROWSER where it stops with the cors error as shown above.
To test this theory, I put some console log messages in the client\node_modules\http-proxy-middleware\lib\index.js functions "shouldProxy" and "middleware", but could not detect any activity from the auth/google end point from the google authorization server response (https://accounts.google.com/o/oauth2/v2/auth).
So I think my theory is wrong and I don't know how I will get this working.
Console log messages displayed on VsCode terminal following request to /auth/google endpoint from the React client are as follows...
http-proxy-middleware - 92 HttpProxyMiddleware - shouldProxy
context [Function: context]
req.url /auth/google
req.originalUrl /auth/google
Trace
at shouldProxy (C:\Users\User\github\GiveMeHopev2\client\node_modules\http-proxy-middleware\lib\index.js:96:13)
at middleware (C:\Users\User\github\GiveMeHopev2\client\node_modules\http-proxy-middleware\lib\index.js:49:9)
at handle (C:\Users\User\github\GiveMeHopev2\client\node_modules\webpack-dev-server\lib\Server.js:322:18)
at Layer.handle [as handle_request] (C:\Users\User\github\GiveMeHopev2\client\node_modules\express\lib\router\layer.js:95:5)
at trim_prefix (C:\Users\User\github\GiveMeHopev2\client\node_modules\express\lib\router\index.js:317:13)
at C:\Users\User\github\GiveMeHopev2\client\node_modules\express\lib\router\index.js:284:7
at Function.process_params (C:\Users\User\github\GiveMeHopev2\client\node_modules\express\lib\router\index.js:335:12)
at next (C:\Users\User\github\GiveMeHopev2\client\node_modules\express\lib\router\index.js:275:10)
at goNext (C:\Users\User\github\GiveMeHopev2\client\node_modules\webpack-dev-middleware\lib\middleware.js:28:16)
at processRequest (C:\Users\User\github\GiveMeHopev2\client\node_modules\webpack-dev-middleware\lib\middleware.js:92:26)
http-proxy-middleware - 15 HttpProxyMiddleware - prepareProxyRequest
req localhost
The Google callback uri is http://localhost:5000/auth/google/callback
This is a listing of my nodejs server code.
dotenv.config();
// express
const app = express();
// cors
app.use(cors())
// passport config
require ('./config/passport')(passport)
// logging
if( process.env.NODE_ENV! !== 'production') {
app.use(morgan('dev'))
}
const conn = process.env.MONGODB_LOCAL_URL!
/**
* dbConnection and http port initialisation
*/
const dbConnnect = async (conn: string, port: number) => {
try {
let connected = false;
await mongoose.connect(conn, { useNewUrlParser: true, useUnifiedTopology: true })
app.listen(port, () => console.log(`listening on port ${port}`))
return connected;
} catch (error) {
console.log(error)
exit(1)
}
}
const port = process.env.SERVERPORT as unknown as number
dbConnnect(conn, port)
//index 02
// Pre Middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }))
const mongoStoreOptions = {
mongoUrl: conn,
collectionName: 'sessions'
}
app.use(
session({
secret: process.env.SESSIONKEY as string,
resave: false,
saveUninitialized: false,
store: MongoStore.create(mongoStoreOptions),
})
)
app.use(passport.initialize())
app.use(passport.session())
// Authentication and Authorisation
const emailScope: string = process.env.GOOGLE_EMAIL_SCOPE as string
//GOOGLE_EMAIL_SCOPE=https://www.googleapis.com/auth/gmail/gmail.compose
const scopes = [
'profile',
emailScope
].join(" ")
app.get('/auth/google', passport.authenticate('google', {
scope: scopes
}));
app.get('/auth/google/callback', passport.authenticate('google', { failureRedirect: '/'}),
(req, res) => {
res.send('Google Login Successful ')
}
)
app.get('/', (req, res) => {
res.send('Hello World');
})
The http-proxy-middleware setupProxy.cjs file. Note the cjs extension. I assume this was because I am using Typescript. It is in the client src folder
const createProxyMiddleware = require('http-proxy-middleware');
module.exports = function (app) {
app.use(createProxyMiddleware('/auth', {target: 'http://localhost:5000'}))
}
And finally the fetch command from the client
async function http(request: RequestInfo): Promise<any> {
try {
const response = await fetch('/auth/google')
const body = await response.json();
return body
} catch (err) { console.log(`Err SignInGoogle`) }
};
And the passport config...
import { PassportStatic} from 'passport';
import {format, addDays} from 'date-fns'
import { IUserDB, IUserWithRefreshToken, ProfileWithJson} from '../interfaces/clientServer'
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const User = require('../models/User')
module.exports = function (passport:PassportStatic) {
const clientID: string = process.env.GOOGLE_CLIENTID as string
const clientSecret: string = process.env.GOOGLE_SECRET as string
const callbackURL: string = process.env.GOOGLE_AUTH_CALLBACK as string
const strategy = new GoogleStrategy(
{
clientID: clientID,
clientSecret: clientSecret,
callbackURL: callbackURL,
proxy: true
},
async (_accesstoken: string, _refreshtoken: string,
profile: ProfileWithJson,
etc