Hi all I have been banging my head researching this for past 2 days with no luck.
This is the error I'm getting when trying to auth with Google Oauth2 Passport strategy from my React app @localhost:3000. I am running a separate app with a node/express server on localhost:3001.
XMLHttpRequest cannot load http:localhost:3001/api/auth/google/login. Redirect from 'http:localhost:3001/api/auth/google/login' to 'https:accounts.google.com/o/oauth2/v2/auth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3001%2Fapi%2Fauth%2Fgoogle%2Fcallback&scope=https%3A%2F%2Fmail.google.com&client_id=***.apps.googleusercontent.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http:localhost:3000' is therefore not allowed access.
createError.js:16
Uncaught (in promise) Error: Network Error at createError (createError.js:16) at XMLHttpRequest.handleError (xhr.js:87)
This is the code Im using in my client to try and login from one of my components:
// BUTTON
<div>
<button className="btn btn-danger" onClick={props.googleAuth}>
Login With Google
</button>
</div>
// STATEFUL COMPONENT METHOD
googleAuth() {
axios.get("http:localhost:3001/api/auth/google/login").then(res => {
console.log("GOOGLE OAUTH 2 RES", res);
});
}
// CONTROLLER
passport.use(
new GoogleStrategy(
{
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: "/api/auth/google/callback",
accessType: "offline"
},
(accessToken, refreshToken, profile, done) => {
const info = {
googleUsername: profile.displayName,
googleAccessToken: accessToken,
googleRefreshToken: refreshToken,
googleEmail: profile.emails[0].value
};
User.findOrCreate({
where: {
googleId: profile.id
},
defaults: info
})
.spread(user => {
if (user) return done(null, user.toAuthJSON);
// this is method that returns a signed JWT off user DB instance.
return done(null, false);
})
.catch(done);
}
)
);
// GOOGLE LOGIN
router.get(
"/login",
passport.authenticate("google", {
scope: [
"https://mail.google.com/",
"https://www.google.com/m8/feeds/",
"email",
"profile"
]
})
);
// GOOGLE CALLBACK
router.get(
"/callback",
passport.authenticate("google", {
session: false,
}), (req, res) => {
res.json(req.user.token)
}
);
Steps I've already taken to try and solve:
And a lot of other tinkering and desperation...
Based on the error, Google is preventing me from making a downstream request from my server and throwing the error (I think)...
What my goals are:
Is this even possible?It should also be noted that I have a dev environment setup:
Server startup with Concurrently (starts client and nodemon server concurrently - client@localhost:3000 makes proxy requests to server@localhost:3001) - not sure if this might be causing any problems?
Any help would be greatly appreciated!
So I was able to solve the issue. The issue is you are using passport.js
for social auth, when you could have simple used something like
https://www.npmjs.com/package/react-social-login
But I would anyways tell how to get your current project working.
https://github.com/j-mcfarlane/Reactjs-SocialAuth-RESTAPI
You need to have the redirect to the UI and not api. So your config will change like below
googleCallbackURL: 'http://localhost:3000/api/auth/google/callback'
Next in your callback, instead of returning data, you will return a redirect like below
jwt.sign(payload, secret, { expiresIn: 220000 }, (err, token) => {
if (err) return console.log(err)
res.redirect("http://localhost:3000/login?token=" + token);
})
I have hardcoded to localhost:3000
but you should get the host
from request and then use it.
Next you will update your App.js
to add another route for /login
, which will call a component SocialLogin
import React, { Component, Fragment } from 'react'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
import PrivateRoute from '../util/PrivateRoute'
// Components
import Navbar from './layout/Navbar'
import Landing from './Landing'
import SocialLogin from './SocialLogin'
import Dashboard from './Dashboard'
class App extends Component {
render() {
return (
<Router>
<Fragment>
<Navbar /><br />
<Route exact path="/" component={Landing} />
<Route exact path="/login" component={SocialLogin} />
<Switch>
<PrivateRoute path="/dashboard" component={Dashboard} />
</Switch>
</Fragment>
</Router>
)
}
}
export default App
The simplest SocialLogin
I wrote is below
import React from 'react'
import qs from 'query-string'
const SocialLogin = (props) => {
console.log(props.location.search)
let params = qs.parse(props.location.search)
window.localStorage.setItem('token', params['token'])
return (<div>Landing Page - {params.token} </div>)
}
export default SocialLogin
Here you have the token and you can continue the flow the way you like it. Also in Google.js
I changed below
<button onClick={this.googleAuth}>Signin With Google</button>
back to your commented
<a href="/api/auth/google">Log in with google</a>
You need redirects to work and you shouldn't AJAX your google auth call, else how will use select an account?
Now after all these fixes, I am able to get the token as shown below
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.