简体   繁体   中英

invalid_request with missing: scope using Google Passportjs on Google Oauth2

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.

  1. 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.

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.

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