问题
An issues has developed in authentication code that was working perfectly up until the beginning of the year, and then seemingly broke with little change on my part, I've tried to regress to a previous version and find the cause with no luck. So I'm Looking for help in fixing the code as it exists today.
I'm using nodejs v0.10.25 Passportjs to provide authentication through both Google and Facebook. My packages:
"config-multipaas": "^0.1.0",
"restify": "^2.8.3",
"googleapis": "~2.1.5",
"mocha": "~2.3.3",
"restify-redirect": "~1.0.0",
"sequelize": "~3.12.2",
"mysql": "~2.9.0",
"passport": "~0.3.2",
"passport-facebook": "~2.0.0",
"passport-local": "~1.0.0",
"passport-google-oauth": "~0.2.0",
"sendgrid-webhook": "0.0.4",
"sendgrid": "~2.0.0",
"restify-cookies": "~0.2.0"
Two weeks ago, while working on another part of the application, I noticed that user signup function was no longer working for either services. Specifically, the Google Oauth2 code returns the following error after the initial consent page.
- That’s an error.
Error: invalid_request
Missing required parameter: scope
Here is the pertinent parts of my strategy definition:
passport.use(new FacebookStrategy({
clientID: siteConfigs.facebook.clientId,
clientSecret: siteConfigs.facebook.clientSecret,
callbackURL: authRoot + 'facebook/callback',
profileFields: ['id','name','emails', 'picture', 'location', 'birthday', 'gender']
},
function(accessToken, refreshToken, profile, done){...}
passport.use(new GooglePlusStrategy({
clientID: siteConfigs.google.clientId,
clientSecret: siteConfigs.google.clientSecret,
callbackURL: authRoot + 'google/callback',
profileFields: ['id','name','emails', 'gender', 'placesLived']
},
function(accessToken, refreshToken, profile, done){...}
The mechanics of the token callback functions are not relevant as the process never gets that far (verified by node debugger and console log statements).
And here are my rest endpoints:
app.get('/auth/facebook', passport.authenticate('facebook', { session: false, scope: ['email']}));
app.get('/auth/google', passport.authenticate('google',
{
scope: ['profile', 'email'],
accessType: 'online',
session: false
})
);
app.get('/auth/:service/callback', function(req, res, next){
console.log('Request:', req.path(), req.getQuery());
passport.authenticate(req.params.service,
function(err, user, info){
var returnPath = '/html/authcallback.html';
if(err)
return res.redirect({
pathname: returnPath,
query: {
error: err
}
}, next);
else
return res.redirect({
pathname: returnPath,
query: {
id: user.id,
created: info
}
}, next);
})(req, res, next);
});
After some initial troubleshooting, I took the approach of using Google's Oauth 2.0 Playground with custom auth and token endpoints (the ones used in my passportjs version) and my own client ID and secret to compare every interaction there with what my code was doing. The initial request for the consent prompt works correctly and matches Playground, and the callback returns an appropriate code, such as code=4/EUnaIvWpLIiHnKUR9WctOJKQ-_iWZ3_H9YeUYx7bJSo
. But the request to exchange code for token fails. using node debugger, to evaluate the redirect request that passport-google-oauth sends back for the token, the URL it builds is:
https://accounts.google.com/o/oauth2/auth?response_type=code&redirect_uri=http://localhost:8080/auth/google/callback&client_id=<ID>
Compare this to a comparable requests from Google Oauth 2.0 Playground, which would look like:
http://www.googleapis.com?code=4/9uaUYjeExmPftgRLsRZ8MCc2e_7YGHow7kvew6Fkypo&redirect_uri=https://developers.google.com/oauthplayground&client_id=<ID>&client_secret=<SECRET>&scope=&grant_type=authorization_code
There are several parameters missing from my query string, the two most important being my code and secret. I would have thought that Google's service would have returned an error for those. Instead, it's returning a error for the missing scope parameter that actually isn't needed for this step in the process anyway (I have no idea why the playground app includes it).
Finally, I'm fairly certain that it's somewhere on my side as the Facebook strategy began failing, as well. After consent, it goes and weird of returning to my callback with multiple codes, then finally returns a TOO_MANY_REDIRECTS error.
So, anyone have any ideas? Once again, this same code was working up until the beginning of the year, then began failing some time afterward.
回答1:
I asked this same question a couple of weeks ago and stumbled across an answer on my own. I'm happy to share it:
Seems I was missing the following code after initializing the server:
api.use(restify.plugins.queryParser({ mapParams: false }));
Once I added that line, I no longer saw the Google error, and the process passed back to my code.
来源:https://stackoverflow.com/questions/34931847/invalid-request-with-missing-scope-using-google-passportjs-on-google-oauth2