GithubHelp home page GithubHelp logo

jaredhanson / passport-google-oauth2 Goto Github PK

View Code? Open in Web Editor NEW
801.0 29.0 157.0 59 KB

Google authentication strategy for Passport and Node.js.

Home Page: https://www.passportjs.org/packages/passport-google-oauth20/?utm_source=github&utm_medium=referral&utm_campaign=passport-google-oauth20&utm_content=about

License: MIT License

Makefile 0.35% JavaScript 99.65%
passport oauth2 google

passport-google-oauth2's Introduction

passport-google-oauth20

Passport strategy for authenticating with Google using OAuth 2.0.

This module lets you authenticate using Google in your Node.js applications. By plugging into Passport, Sign In with Google can be easily and unobtrusively integrated into any application or framework that supports Connect-style middleware, including Express.

๐Ÿง  Understanding OAuth 2.0 โ€ข :heart: Sponsors

Developed by Jared Hanson.

Advertisement
The Complete Node.js Developer Course
Learn Node. js by building real-world applications with Node, Express, MongoDB, Jest, and more!

Install

$ npm install passport-google-oauth20
TypeScript type declarations
$ npm install @types/passport-google-oauth20

Usage

Register Application

The Google strategy authenticates users using their Google account. Before your application can make use of Google's authentication system, you must first register your app to use OAuth 2.0 with Google APIs. Once registered, a client ID and secret will be issued which are used by Google to identify your app.

Configure Strategy

Once you've registered your application, the strategy needs to be configured with your application's client ID and secret, along with its OAuth 2.0 redirect endpoint.

The strategy takes a verify function as an argument, which accepts accessToken, refreshToken, and profile as arguments. accessToken and refreshToken are used for API access, and are not needed for authentication. profile contains the user's profile information stored in their Google account. When authenticating a user, this strategy uses the OAuth 2.0 protocol to obtain this information via a sequence of redirects and API requests to Google.

The verify function is responsible for determining the user to which the Google account belongs. In cases where the account is logging in for the first time, a new user record is typically created automatically. On subsequent logins, the existing user record will be found via its relation to the Google account.

Because the verify function is supplied by the application, the app is free to use any database of its choosing. The example below illustrates usage of a SQL database.

var GoogleStrategy = require('passport-google-oauth20');

passport.use(new GoogleStrategy({
    clientID: process.env['GOOGLE_CLIENT_ID'],
    clientSecret: process.env['GOOGLE_CLIENT_SECRET'],
    callbackURL: 'https://www.example.com/oauth2/redirect/google',
    scope: [ 'profile' ],
    state: true
  },
  function verify(accessToken, refreshToken, profile, cb) {
    db.get('SELECT * FROM federated_credentials WHERE provider = ? AND subject = ?', [
      'https://accounts.google.com',
      profile.id
    ], function(err, cred) {
      if (err) { return cb(err); }
      
      if (!cred) {
        // The account at Google has not logged in to this app before.  Create a
        // new user record and associate it with the Google account.
        db.run('INSERT INTO users (name) VALUES (?)', [
          profile.displayName
        ], function(err) {
          if (err) { return cb(err); }
          
          var id = this.lastID;
          db.run('INSERT INTO federated_credentials (user_id, provider, subject) VALUES (?, ?, ?)', [
            id,
            'https://accounts.google.com',
            profile.id
          ], function(err) {
            if (err) { return cb(err); }
            
            var user = {
              id: id,
              name: profile.displayName
            };
            return cb(null, user);
          });
        });
      } else {
        // The account at Google has previously logged in to the app.  Get the
        // user record associated with the Google account and log the user in.
        db.get('SELECT * FROM users WHERE id = ?', [ cred.user_id ], function(err, user) {
          if (err) { return cb(err); }
          if (!user) { return cb(null, false); }
          return cb(null, user);
        });
      }
    });
  }
));

Define Routes

Two routes are needed in order to allow users to log in with their Google account. The first route redirects the user to the Google, where they will authenticate:

app.get('/login/google', passport.authenticate('google'));

The second route processes the authentication response and logs the user in, after Google redirects the user back to the app:

app.get('/oauth2/redirect/google',
  passport.authenticate('google', { failureRedirect: '/login', failureMessage: true }),
  function(req, res) {
    res.redirect('/');
  });

Documentation

Examples

Related Packages

Authors

License

The MIT License

Copyright (c) 2012-2023 Jared Hanson

passport-google-oauth2's People

Contributors

ezintz avatar jaredhanson avatar keith24 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

passport-google-oauth2's Issues

405 Error

Sometimes when using this library I get 405 errors from Google (and then sometimes it works just fine):

Request URL:https://accounts.google.com/o/oauth2/v2/auth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauth%2Fcallback%2Fgoogle&scope=profile&client_id=637989435204-fivtb7isf82lanreup4qsuhvn3s7hl15.apps.googleusercontent.com
Request Method:OPTIONS
Status Code:405

Which are then followed by:

Failed to load https://accounts.google.com/o/oauth2/v2/auth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauth%2Fcallback%2Fgoogle&scope=profile&client_id=637989435204-fivtb7isf82lanreup4qsuhvn3s7hl15.apps.googleusercontent.com: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 405. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

All of that only occurs client-side (I don't see any errors in my server log). The GitHub page makes no mention of why I'd get XSS errors, why they'd only be intermittent, or how I can fix them. It seems like sometimes restarting my server and closing the tab in my browser fixes things, and other times it doesn't; that's as far as I've gotten.

Any assistance would be appreciated.

accessType=offline & approvalPrompt=force doesn't work in Chrome

When I call passport.authenticate for google, configured with the passport-google-oauth2 config, the Google OAuth confirmation screen is not forced in Chrome. It is forced in Safari. This is required to get the google refresh token on a users 2nd + time authenticating. Wondering if there is something we can do within the scope of this library to help force the prompt. Thanks!

Cannot get refresh token

Even though I tried many times with several different users, I couldn't get refresh token. My code looks like the following.

passport.use('google', new GoogleStrategy({ clientID: '...', clientSecret: '...', callbackURL: '...', passReqToCallback: true, accessType: 'offline' }, (req, accessToken, refreshToken, profile, cb) => { ... }));

GSuite Hosted domains return names undefined second time login.

I encountered a problem.

when i try to login with a GSuite for education domain, the first time, i get a full profile with displayName and names, i get AccessToken and RefreshToken as well :

{ id: '107441755XXXXXXXXXX', displayName: 'MyDisplayName', name: { familyName: 'MyFiName', givenName: 'MyGiName' }, isPerson: true, }

But the second time i login the profile is missing the names and displayName:

{ id: '107441755XXXXXXXXXX', displayName: '', name: { familyName: '', givenName: '' }, isPerson: true, }

This happens only for hosted domains. if a try with a @gmail account, everything seems to work just fine.

Any idea what the problem would be, or how can i debug this?

Error with Google Sign-in

Authentication fails with Error

I have some pretty straightforward boilerplate authentication code that fails,

router.get('/auth/google',
  passport.authenticate('google', { scope: ['profile', 'email'] }));

router.get('/auth/google/return',
  passport.authenticate('google', { failureRedirect: '/' }),
  function (req, res) {
    res.redirect('/');
  });

Upon being returned to /auth/google/return I'm given a vague Error,

Error
    at /Users/apetcoff/i liek 2 progrmam/my-project/node_modules/passport-google-oauth20/lib/strategy.js:95:21
    at passBackControl (/Users/apetcoff/i liek 2 progrmam/my-project/node_modules/oauth/lib/oauth2.js:132:9)
    at IncomingMessage.<anonymous> (/Users/apetcoff/i liek 2 progrmam/my-project/node_modules/oauth/lib/oauth2.js:157:7)
    at emitNone (events.js:91:20)
    at IncomingMessage.emit (events.js:185:7)
    at endReadableNT (_stream_readable.js:974:12)
    at _combinedTickCallback (internal/process/next_tick.js:74:11)
    at process._tickDomainCallback (internal/process/next_tick.js:122:9)

Facebook and Twitter authentication both work fine.

integrate with google calendar api

How can i access the google calendar api?
I see that profile includes the google plus information but how can i include the calendar information?

}, (accessToken, refreshToken, profile, done) => {

or do i need a new strategy?

I already have the user being authenticated and I can retrieve their name, image, email, etc.
How can i also retrieve their calendar events list? The api is enabled in my google developer console.

Bad Gateway on nginx

I'm implementing this strategy using the Facebook example from the link on the README.

When I try it locally, things seem to be working well. When I deploy it to my Ubuntu production server, I get a 502 Bad Gateway error during the redirect callback from Google to the /login/google/return endpoint.

I have written a more detailed breakdown of the problem I'm observing here http://stackoverflow.com/questions/38471404/passport-js-express-google-oauth-502-bad-gateway-on-nginx

I realize that this could be due to nginx and not related to this project. However, I was hoping that maybe someone on here might be more familiar and could help me through debugging this issue. Any help would be greatly appreciated.

Thanks.

redirect_uri_mismatch 400 error but only on mobile?

Using passport-google-oauth2 v2

I have been deploying my apps on Heroku and I have gotten the Oauth google process to work. However the oauth process only works on desktop browsers (chrome,safari)

Once I try doing the OAUTH process on my iOS safari browser I get an automatic redirect_uri_mismatch 400 error . The OAUTH process however does work on my mac airbook browsers. Even my old apps where I was able to do the OAUTH process successfully on mobile browsers before have stopped working and I just get a 400 error right away.

TokenError: Code was already redeemed and TokenError: Bad Request

I have a pretty basic passport setup as you can see below. Every once in a while I get two different errors. TokenError: Code was already redeemed and TokenError: Bad Request for reasons I cannot seem to find.

I've looked around a lot (1 week) for possible solutions but am yet to find one which works.

Do you see anything wrong with the current code?

app.get('/auth/google', redirect, passport.authenticate('google', { scope: ['profile', 'email'] }));

app.get('/auth/google/callback', passport.authenticate('google', { failureRedirect: '/' }),
  function(req, res) {
    res.redirect('/');
  }
);

Here are the two errors:

TokenError: Bad Request 
  at Strategy.OAuth2Strategy.parseErrorResponse (/app/node_modules/passport-oauth2/lib/strategy.js:320:12) 
  at Strategy.OAuth2Strategy._createOAuthError (/app/node_modules/passport-oauth2/lib/strategy.js:367:16) 
  at /app/node_modules/passport-oauth2/lib/strategy.js:166:45 
  at /app/node_modules/oauth/lib/oauth2.js:177:18 
  at passBackControl (/app/node_modules/oauth/lib/oauth2.js:123:9) 
  at IncomingMessage.<anonymous> (/app/node_modules/oauth/lib/oauth2.js:143:7) 
  at emitNone (events.js:85:20) 
  at IncomingMessage.emit (events.js:179:7) 
  at endReadableNT (_stream_readable.js:913:12) 
  at _combinedTickCallback (internal/process/next_tick.js:74:11) 
  at process._tickCallback (internal/process/next_tick.js:98:9)



TokenError: Code was already redeemed. 
      at Strategy.OAuth2Strategy.parseErrorResponse (/app/node_modules/passport-oauth2/lib/strategy.js:320:12) 
      at Strategy.OAuth2Strategy._createOAuthError (/app/node_modules/passport-oauth2/lib/strategy.js:367:16) 
      at /app/node_modules/passport-oauth2/lib/strategy.js:166:45 
      at /app/node_modules/oauth/lib/oauth2.js:177:18 
      at passBackControl (/app/node_modules/oauth/lib/oauth2.js:123:9) 
      at IncomingMessage.<anonymous> (/app/node_modules/oauth/lib/oauth2.js:143:7) 
      at emitNone (events.js:85:20) 
      at IncomingMessage.emit (events.js:179:7) 
      at endReadableNT (_stream_readable.js:913:12) 
      at _combinedTickCallback (internal/process/next_tick.js:74:11) 
      at process._tickCallback (internal/process/next_tick.js:98:9) 

Whitelist specific domains

Is it possible to whitelist specific domains?

For example, only people with '@someaddress.com' can log in

Breaking changes in 2.0?

Hello,

I was wondering if there's a list of breaking changes to upgrade from version 1 to 2

Thanks

Error while reading email id

Hi @jaredhanson , I am trying to read user email id after login, I am able to get profile id and display name but not able to read user email using either profile.emails[0].vlaue or profile.email.

please help me on this.

passport.use(
new GoogleStrategy(
{
clientID: XXXXXXXXXXX
clientSecret: XXXXXXXXXXX,
callbackURL: XXXXXXXXXXXXXX
enableProof: true,
profileFields: [
"id",
"email",
"emails",
"gender",
"link",
"locale",
"name",
"timezone",
"updated_time",
"verified"
],
enableProof: true,
scope: [
"profile",
"emails",
"user:email",
"https://www.googleapis.com/auth/plus.me",
"https://www.googleapis.com/auth/plus.login",
"https://www.googleapis.com/auth/plus.profile.emails.read",
]
},
function(accessToken, refreshToken, profile, cb) {
console.log(profile gender is ${profile.gender}); // Returning Gender
console.log(user display name is ${profile.displayName}); // Returning Display Name
console.log(user email is ${ profile.email}); // Returning Undefined
return cb(profile);
}
)
);

Getting a Error 400

I'm getting a error 400 from google

Error: invalid_request
Missing required parameter: scope

Looks like the library does not send the scope parameter. Is there anyway to set it?

"prompt: 'none'" not working

This is my setup:

passport.use(new GoogleStrategy({  
    clientID: process.env.CLIENT_ID,
    clientSecret: process.env.CLIENT_SECRET,
    callbackURL: process.env.REDIRECT_URL,
    prompt: 'select_account',
    accessType: 'offline',
    scope: ['profile', 'email', 'https://www.googleapis.com/auth/calendar']
}, (accessToken, refreshToken, params, profile, done) => {
    User.findOne({ oauthID: profile.id }, function(err, user) {
        if(err) {
            console.log(err);  // handle errors!
        }
        if (!err && user !== null) {
            done(null, user);
        } else {
            user = new User({
                email: profile.emails[0].value,
                oauthID: profile.id,
                google: {
                    email: profile.emails[0].value,
                    id: profile.id,
                    token: accessToken,
                    refresh_token: refreshToken,
                    token_type: params.token_type,
                    expires_in: params.expires_in
                },
                created: Date.now()
            });
            user.save(function(err) {
                if(err) {
                    console.log(err); 
                } else {
                    console.log("saving user ...");
                    done(null, user);
                }
            });
        }
    });
}));

How ever I keep getting the consent form. I've tried using prompt: 'none' as well but that doesn't work either.
What I want to achieve is something that I kind of expected was going to be dealt with automatically but have proven much harder than I expected... If I already have an access_token and refresh_token for the user I don't want them to have to consent again, just simply log them in.
I thought about doing 2 different strategies and use one for signing up and one for signing in, but then again, prompt: 'none' doesn't work so no luck there.

Anyone know what I'm doing wrong?

Refresh token undefined

Hi,

I'm using passport to oAuth with google. In my callback after the user has logged in, although the parameters are: (request, accessToken, refreshToken, profile, done), the refreshToken is undefined while every other parameter is what it should be.
Whats wrong with the code?

This is the strategy config:

    clientID: process.env.GoogleClientID,
    clientSecret: process.env.GoogleClientSecret,
    callbackURL: process.env.GoogleCallbackURL,
    accessType: 'offline',
    prompt: 'consent',
    scope: [
      'https://www.googleapis.com/auth/drive',
      'https://www.googleapis.com/auth/userinfo.profile',
      'profile',
      'https://www.googleapis.com/auth/plus.login',
      'https://www.googleapis.com/auth/userinfo.email'],
    passReqToCallback: true

I already tried to delete all the cookies, and the app from the permissions...
https://myaccount.google.com/u/0/permissions?pli=1

Thanks for your help

Refresh Token not being returned, despite trying multiple recommended options

I cannot get the refresh_token to be populated at any point, using the following strategy (trying lots of options):


const GoogleStrategy = require('passport-google-oauth20').Strategy;

let googleStrategy = new GoogleStrategy({
    clientID: app.config.get('GOOGLE_CLIENT_ID'),
    clientSecret: app.config.get('GOOGLE_CLIENT_SECRET'),
    callbackURL: app.config.get('GOOGLE_CALLBACK_URL'),

    accessType: 'offline', 
    approvalPrompt: 'force',

    access_type: 'offline',
    prompt: 'consent',

    customHeaders: {
      access_type: 'offline',
      accessType: 'offline',
      approvalPrompt: 'force',
      prompt: 'consent'
    },
    scope: [
      'https://www.googleapis.com/auth/userinfo.email',
      'https://www.googleapis.com/auth/youtube',
      'https://www.googleapis.com/auth/youtube.upload',
      'https://www.googleapis.com/auth/youtubepartner'
    ]
  },
  function(accessToken, refreshToken, profile, done) {
    console.log('Starting GoogleStrategy2!');
    console.log('accessToken', accessToken);
    console.log('refreshToken', refreshToken);
    if(!refreshToken){
      console.log('No Refresh Token');
      return done('NO REFRESH TOKEN');
    }
    done(null, {
      profile,
      accessToken,
      refreshToken
    })
  }
)

Am I missing something, or has the option changed down the line somewhere?

InternalOAuthError: failed to fetch user profile

Using both https://github.com/mjhea0/passport-examples and https://github.com/barberboy/passport-google-oauth2-example I am getting the following error :-

InternalOAuthError: failed to fetch user profile
at C:\Users\aaron\Tests\JavaScript\Facebook\passport-examples\node_modules\passport-google-oauth2\lib\oauth2.js:92:28
at passBackControl (C:\Users\aaron\Tests\JavaScript\Facebook\passport-examples\node_modules\oauth\lib\oauth2.js:132:9)
at IncomingMessage. (C:\Users\aaron\Tests\JavaScript\Facebook\passport-examples\node_modules\oauth\lib\oauth2.js:157:7)
at emitNone (events.js:91:20)
at IncomingMessage.emit (events.js:185:7)
at endReadableNT (_stream_readable.js:974:12)
at _combinedTickCallback (internal/process/next_tick.js:74:11)
at process._tickCallback (internal/process/next_tick.js:98:9)

TypeError: Cannot read property 'encrypted' of undefined

I have done everything as described below, and after adding all my secrets and making call ' curl http://localhost:3000/auth/google' I get en error:

error: TypeError: Cannot read property 'encrypted' of undefined
at Object.exports.originalURL (/usr/src/app/node_modules/passport-oauth2/lib/utils.js:27:28)
at Strategy.OAuth2Strategy.authenticate (/usr/src/app/node_modules/passport-oauth2/lib/strategy.js:141:39)
at attempt (/usr/src/app/node_modules/passport/lib/middleware/authenticate.js:361:16)
at authenticate (/usr/src/app/node_modules/passport/lib/middleware/authenticate.js:362:7)
at dispatch (/usr/src/app/node_modules/koa-router/node_modules/koa-compose/index.js:44:32)
at next (/usr/src/app/node_modules/koa-router/node_modules/koa-compose/index.js:45:18)
at /usr/src/app/node_modules/koa-router/lib/router.js:346:16
at dispatch (/usr/src/app/node_modules/koa-router/node_modules/koa-compose/index.js:44:32)
at /usr/src/app/node_modules/koa-router/node_modules/koa-compose/index.js:36:12
at dispatch (/usr/src/app/node_modules/koa-router/lib/router.js:351:31)
at dispatch (/usr/src/app/node_modules/koa-compose/index.js:42:32)
at errorCatcher (/usr/src/app/src/middlewares/errorCatcher.js:5:11)
at dispatch (/usr/src/app/node_modules/koa-compose/index.js:42:32)
at bodyParser (/usr/src/app/node_modules/koa-bodyparser/index.js:86:11)
at process._tickCallback (internal/process/next_tick.js:68:7)

How to access auth object for using google apis

I am trying to use the google drive api and it needs an auth object that contains the tokens among other things how do I access said object after authentication is complete using this strategy

Thank you,

Passport + Google OAuth2 + AWS Cognito

Hi there

I'm getting this
NotAuthorizedException: Invalid login token. Not a valid OpenId Connect identity token.

when trying to use the accessToken you return to create an Identity on Cognito, any ideas?

I found on AWS forum this

UPDATE: Finally figured out the issue. The token I was using was incorrect. It should be id_token that is returned from Google and not the access_token or refresh_token. 

any ideas of what that could be or how it could be fixed?

thanks!

404 sent to client (browser) during google callback, but the user data is retrieved.

I also posted this in the koa-passport, just in case the error may be on their side. However, as koa-passport is a simple augmentation on the req object, the error is most likely in this module?

When calling passport.authenticate(...) in the OAuth2 callback stage of the authentication sequence for Google OAuth2 as follows:

const GoogleStrategy = require('passport-google-oauth2').Strategy
passport.use(new GoogleStrategy({
    scope: ['email', 'profile'],
    clientID: process.env.GOOGLE_CLIENT_ID,
    clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    callbackURL: 'http://localhost:' + 7000 + '/auth/google/callback'
  },
  (accessToken, refreshToken, profile, done) => {
    console.log(profile)
    fetchUser().then(user => done(null, user))
  }
))


app.use(route.get('/auth/google', async (ctx, next) => {
  console.log(`/auth/google/singin called with\n ctx -> ${JSON.stringify(ctx)} && next -> ${next}`)
    console.log(`ctx.req.headers -> ${JSON.stringify(ctx.req.headers)}`)
    console.log(`ctx.req.rawHeaders -> ${ctx.req.rawHeaders}`)
    passport.authenticate('google')(ctx,next)
  }
))
  
app.use(route.get('/auth/google/callback', async (ctx, next) => {
  passport.authenticate('google', async (err, user, info) => {
    console.log(`/auth/google/signin/callback -> passport.authenticate('google') callback called with\nerr -> ${JSON.stringify(err)}\nuser -> ${JSON.stringify(user)}\ninfo -> ${JSON.stringify(info)}`)
    if (user === false) {
      ctx.redirect('/')
      await next()
    } else {
      ctx.login(user)
      ctx.redirect('/app')
      await next()
    }
  })(ctx, next)
}))

Koa is sending 404 headers to the client (browser),

screen shot 2017-04-17 at 6 17 08 pm

but the anonymous function callback is called with the actual user data.

The debug output shows the sequence of calls (removed personal info):

  <-- GET /favicon.ico
  --> GET /favicon.ico 302 6ms 33b
  <-- GET /
  --> GET / 200 5ms 719b
  <-- GET /auth/google
/auth/google/singin called with
 ctx -> {"request":{"method":"GET","url":"/auth/google","header":{"host":"localhost:7000","connection":"keep-alive","upgrade-insecure-requests":"1","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36","accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8","dnt":"1","referer":"http://localhost:7000/","accept-encoding":"gzip, deflate, sdch, br","accept-language":"en-US,en;q=0.8,ja;q=0.6","cookie":"koa.sid.sig=O9oTTBivYar3gy7JuZtdpDgvTO0"}},"response":{"status":404,"message":"Not Found","header":{}},"app":{"subdomainOffset":2,"proxy":true,"env":"development"},"originalUrl":"/auth/google","req":"<original node req>","res":"<original node res>","socket":"<original node socket>"} && next -> function next() {
          return dispatch(i + 1)
        }
ctx.req.headers -> {"host":"localhost:7000","connection":"keep-alive","upgrade-insecure-requests":"1","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36","accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8","dnt":"1","referer":"http://localhost:7000/","accept-encoding":"gzip, deflate, sdch, br","accept-language":"en-US,en;q=0.8,ja;q=0.6","cookie":"koa.sid.sig=O9oTTBivYar3gy7JuZtdpDgvTO0"}
ctx.req.rawHeaders -> Host,localhost:7000,Connection,keep-alive,Upgrade-Insecure-Requests,1,User-Agent,Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36,Accept,text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8,DNT,1,Referer,http://localhost:7000/,Accept-Encoding,gzip, deflate, sdch, br,Accept-Language,en-US,en;q=0.8,ja;q=0.6,Cookie,koa.sid.sig=O9oTTBivYar3gy7JuZtdpDgvTO0
  --> GET /auth/google 302 4ms 0b
  <-- GET /auth/google/callback?code=4/vE4A-Yl3nZS07-x61cgapHEf2UhX3b-ptn4K0wdSLv0
  --> GET /auth/google/callback?code=4/vE4A-Yl3nZS07-x61cgapHEf2UhX3b-ptn4K0wdSLv0 404 9ms -
  <-- GET /favicon.ico
  --> GET /favicon.ico 302 2ms 33b
  <-- GET /
  --> GET / 200 22ms 719b
{ provider: 'google',
  id: 'XXXXXXXXXXXXXXX',
  displayName: XXXXXXXXXXXXXXX',
  name: { familyName: 'XXXXXXXXXXXXXXX', givenName: 'XXXXXXXXXXXXXXX' },
  isPerson: true,
  isPlusUser: true,
  language: 'en',
  emails: [ { value: 'XXXXXXXXXXXXXXX', type: 'account' } ],
  email: 'XXXXXXXXXXXXXXX',
  gender: 'XXXXXXXXXXXXXXX',
  photos: [ { value: 'https://lh5.googleusercontent.com/XXXXXXXXXXX/photo.jpg?sz=50' } ],
  _raw: '{\n "kind": "plus#person",\n "etag": "\\"XXXXXXXXXXXXXX\\"",\n "gender": "XXXXXXXXX",\n "emails": [\n  {\n   "value": "XXXXXXXXXXXXXXX",\n   "type": "account"\n  }\n ],\n "objectType": "person",\n "id": "XXXXXXXXXXXXXXX",\n "displayName": "XXXXXXXXXXXXXXX",\n "name": {\n  "familyName": "XXXXXXXXXXXXXXX",\n  "givenName": "XXXXXXXXXXXXXXX"\n },\n "url": "https://plus.google.com/XXXXXXXXXXXXXXX",\n "image": {\n  "url": "https://lh5.googleusercontent.com/XXXXXXXXXXXXXXX/photo.jpg?sz=50",\n  "isDefault": false\n },\n "isPlusUser": true,\n "language": "en",\n "circledByCount": 0,\n "verified": false\n}\n',
  _json: 
   { kind: 'plus#person',
     etag: '"XXXXXXXXXXXXXXX"',
     gender: 'XXXXXXXXXXXXXXX',
     emails: [ [Object] ],
     objectType: 'person',
     id: 'XXXXXXXXXXXXXXX',
     displayName: 'XXXXXXXXXXXXXXX',
     name: { familyName: 'XXXXXXXXXXXXXXX', givenName: 'XXXXXXXXXXXXXXX' },
     url: 'https://plus.google.com/XXXXXXXXXXXXXXX',
     image: 
      { url: 'https://lh5.googleusercontent.com/XXXXXXXXXXXXXXX/photo.jpg?sz=50',
        isDefault: false },
     isPlusUser: true,
     language: 'en',
     circledByCount: 0,
     verified: false } }
/auth/google/signin/callback -> passport.authenticate('google') callback called with
err -> null
user -> {"id":1,"username":"test","password":"test"}
info -> {}
(node:54360) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 4): Error: Can't set headers after they are sent.

Error when getting the callback

I am trying to test google oauth, the login page does open, but the callback provoke a exception.
I used the code from the facebook example, created the app on the developper console and enabled the G+ API. I also tried the strategy without the G+ API as described in [https://github.com//issues/7](this issue).

Error
	at Strategy.OAuth2Strategy.parseErrorResponse (/home/user/Git/mbt/express-4.x-facebook-example/node_modules/passport-oauth2/lib/strategy.js:329:12)
	at Strategy.OAuth2Strategy._createOAuthError (/home/user/Git/mbt/express-4.x-facebook-example/node_modules/passport-oauth2/lib/strategy.js:376:16)
	at /home/user/Git/mbt/express-4.x-facebook-example/node_modules/passport-oauth2/lib/strategy.js:166:45
	at /home/user/Git/mbt/express-4.x-facebook-example/node_modules/oauth/lib/oauth2.js:191:18
	at passBackControl (/home/user/Git/mbt/express-4.x-facebook-example/node_modules/oauth/lib/oauth2.js:132:9)
	at IncomingMessage.<anonymous> (/home/user/Git/mbt/express-4.x-facebook-example/node_modules/oauth/lib/oauth2.js:157:7)
	at emitNone (events.js:110:20)
	at IncomingMessage.emit (events.js:207:7)
	at endReadableNT (_stream_readable.js:1045:12)
	at _combinedTickCallback (internal/process/next_tick.js:138:11)

request documentation or fix hostedDomain / hd parameter?

I'm developing an application using Google authentication to allow a hosted domain users only,
google documentation says it support hd parameter to allow this restriction, this library seems have this support, but with this new GoogleStrategy({ ... }) with hostedDomain or hd it doesn't make a difference, I don't see &hd=... parameter on the redirection url, when I manually append with &hd=custom.com that works;
So wonder is this passing hostedDomain to constructor the correct way to use it? request an example in REDME.md to clarify it; or fix if it's broken

https://github.com/jaredhanson/passport-google-oauth2/blob/master/lib/strategy.js#L159-L164
https://developers.google.com/identity/protocols/OpenIDConnect#hd-param
https://developers.google.com/identity/sign-in/web/reference

passport.use(new GoogleStrategy({
  clientID: config.get('OAUTH2_CLIENT_ID'),
  clientSecret: config.get('OAUTH2_CLIENT_SECRET'),
  callbackURL: config.get('OAUTH2_CALLBACK'),
  hostedDomain: config.get('OAUTH2_DOMAIN') || 'custom.com',
  // or hd: config.get('OAUTH2_DOMAIN') || 'custom.com',
  accessType: 'offline'
}, function (accessToken, refreshToken, profile, cb) {
   ...
   // here have to double validate profile.emails instead has such domain,
   // I found profile._json object has a domain attribute, like
       profile: { id: ..., displayName: ..., emails: [ ... ], photos: { ... }, _json: { domain: 'custom.com' } }
   // wonder why not expose the domain key to profile object?

Social login error after user record is deleted from backend/database (stale cookies causing problem)

I'm submitting a...


[X] Bug report  
[X] Feature request

Current behavior

If a user is registered using social login (Google/Facebook).
And the user was browsing website from machine M1 (passport set cookies in user's browser). And User logs out.
For some reason (say..!!user deleted his account from a different machine M2) if the user's record is deleted from database.
Now... If User tried to log in again using social login (Google/Facebook) on machine M1, passport gives an error (remember passport stored cookies in machine M1's browser).
However if cookies are deleted, this error wont occur

Expected behavior

Exprected behavior would be if user can not be deserialized from the userid which is received in request body (because there were cookies, I would like to call them stale cookeis).
In that case user should be redirected to Google/Facebook login page (if he's not logged in). If he's logged in the permission grant/authorization page should be shown.

Minimal reproduction of the problem with instructions

Steps to reproduce

  1. Create a website which allows users to register through Google/Facebook
  2. register using Google/Facebook
  3. Login with above registered user
  4. Logout from the session
  5. Delete user record from backend, using backend(sql) queries. This is to fake the behavior when user deletes his account from a different machine
  6. Now try logging in using the same user (same social login)
  7. You will receive following error
    Error: Failed to deserialize user out of session at pass (E:\tmts\node_modules\passport\lib\authenticator.js:344:19) at deserialized (E:\tmts\node_modules\passport\lib\authenticator.js:349:7) at E:\tmts\config\passport-setup.js:23:9 at at process._tickCallback (internal/process/next_tick.js:188:7)

What is the motivation / use case for changing the behavior?

I want to allow users to be able to delete their account from my website. And at some later point of time if they want to register again, there shouldn't be any problem.

Environment

Browser:

  • Chrome (desktop) version XX
  • Chrome (Android) version XX

For Tooling issues:

  • Node version: v8.9.4
  • Platform: Windows 10 & Ubuntu 14.04

Checking for logged in user fails, how should I check

My code returns a user but when I try to use the 'logged in' code I get back false. What am I missing?

router.get('/loggedin', function (req, res) {
res.send(req.isAuthenticated() ? req.user.username : '0');
});

Should I be using different code to check for a Google user being logged?

Thanks

Dynamic authentication options.

Based on the request, I'd like to be able to configure authentication options.

E.g., to dynamically set the scope or state params (the latter, for example, to encode different success path redirects).

router.get('/login/' + providerId, passport.authenticate(providerId, {
  // Use request to configure params.
  scope: request => decodeURI(request.params.scope)
}));

Is this possible without a change to the Passport API?

Query on Google+ deprecation

Does the announcement here mean that this auth won't work any more? I use one Google+ as a test account for our project and it's definitely Google+ related.

Thanks for the insight.

InternalOAuthError

WHEN I TRYING TO LOGIN WITH GOOGLE OAUTH2 I SEE THIS ERROR

InternalOAuthError: Failed to obtain access token
at Strategy.OAuth2Strategy._createOAuthError (/Users/kprat1/learning/passportexamples2/passport-examples/node_modules/passport-oauth2/lib/strategy.js:370:17)
at /Users/kprat1/learning/passportexamples2/passport-examples/node_modules/passport-oauth2/lib/strategy.js:166:45
at /Users/kprat1/learning/passportexamples2/passport-examples/node_modules/oauth/lib/oauth2.js:177:18
at ClientRequest. (/Users/kprat1/learning/passportexamples2/passport-examples/node_modules/oauth/lib/oauth2.js:148:5)
at emitOne (events.js:90:13)
at ClientRequest.emit (events.js:182:7)
at TLSSocket.socketErrorListener (_http_client.js:295:9)
at emitOne (events.js:90:13)
at TLSSocket.emit (events.js:182:7)
at emitErrorNT (net.js:1250:8)
at _combinedTickCallback (node.js:377:13)
at process._tickCallback (node.js:401:11)

Invalidate token on logout

Is there a recommended pattern to invalidate the token through Google on logout? Atm, if a user logs in, Google requests for basic profile information. If they log out, then log back in, it requests for "offline access," which isn't very clear, I think. I'd rather it always say the same thing, whether you've never logged in before or if you've logged in and out many times.

The solution, I've read, is to send a request to Google to invalidate the token, but this requires the token, and I can't seem to access the token from the req.session Object in the /logout route handler.

Has anyone felt the need to do this in the past? If so, how did you go about it?

Does not work in strict mode

/web/shodan/node_modules/passport-google-oauth20/lib/errors/googleplusapierror.js:14
Error.captureStackTrace(this, arguments.callee);
^

TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
at new GooglePlusAPIError (/web/shodan/node_modules/passport-google-oauth20/lib/errors/googleplusapierror.js:14:43)
at /web/shodan/node_modules/passport-google-oauth20/lib/strategy.js:95:21
at passBackControl (/web/shodan/node_modules/oauth/lib/oauth2.js:132:9)
at IncomingMessage. (/web/shodan/node_modules/oauth/lib/oauth2.js:157:7)
at emitNone (events.js:111:20)
at IncomingMessage.emit (events.js:208:7)
at endReadableNT (_stream_readable.js:1064:12)
at _combinedTickCallback (internal/process/next_tick.js:138:11)
at process._tickCallback (internal/process/next_tick.js:180:9)

failureCallback

I guess it's more related to passport or express, but can't the api provide a callback for failure too?

app.get('/auth/google/callback', 
  passport.authenticate('google', { failureRedirect: '/login' }),
  function(req, res) {
    // Successful authentication, redirect home.
    res.redirect('/');
  });

could be:

app.get('/auth/google/callback', 
  passport.authenticate('google', {
    success(req, res) {  // Successful authentication, redirect home.
      res.redirect('/');
    },
    failure(req, res) {  // Failed authentication, redirect login.
      // do stuff...
      res.send(...)
      //res.redirect('/login');
  })
);

linked to #5

Rewrite to Google Identity Platform?

More of a query to find out if a rewrite is in the works.
Reference: https://developers.google.com/+/api-shutdown

The googleplus.js file references the API being shutdown by google.

/**
 * Parse profile.
 *
 * Parses user profiles as fetched from Google's Google+ API.
 *
 * The amount of detail in the profile varies based on the scopes granted by the
 * user.  The following scope values add additional data:
 *
 *     `https://www.googleapis.com/auth/plus.login` - recommended login scope
 *     `profile` - basic profile information
 *     `email` - email address
 *
 * References:
 *   - https://developers.google.com/+/web/api/rest/latest/people/get
 *   - https://developers.google.com/+/web/api/rest/
 *   - https://developers.google.com/+/web/api/rest/oauth
 *
 * @param {object|string} json
 * @return {object}
 * @access public
 */
exports.parse = function(json) {
  if ('string' == typeof json) {
    json = JSON.parse(json);
  }
  
  var profile = {}
    , i, len;
  profile.id = json.id;
  profile.displayName = json.displayName;
  if (json.name) {
    profile.name = { familyName: json.name.familyName,
                     givenName: json.name.givenName };
  }
  if (json.emails) {
    profile.emails = [];
    for (i = 0, len = json.emails.length; i < len; ++i) {
      profile.emails.push({ value: json.emails[i].value, type: json.emails[i].type })
    }
  }
  if (json.image) {
    profile.photos = [{ value: json.image.url }];
  }
  profile.gender = json.gender;
  
  return profile;
};

Same with strategy.js. This will render this library useless until rewritten.

function Strategy(options, verify) {
  options = options || {};
  options.authorizationURL = options.authorizationURL || 'https://accounts.google.com/o/oauth2/v2/auth';
  options.tokenURL = options.tokenURL || 'https://www.googleapis.com/oauth2/v4/token';

  OAuth2Strategy.call(this, options, verify);
  this.name = 'google';
// this endpoint is part of the shutdown
  this._userProfileURL = options.userProfileURL || 'https://www.googleapis.com/plus/v1/people/me';
  
  var url = uri.parse(this._userProfileURL);
  if (url.pathname.indexOf('/userinfo') == (url.pathname.length - '/userinfo'.length)) {
    this._userProfileFormat = 'openid';
  } else {
    this._userProfileFormat = 'google+'; // Google Sign-In
  }
}

Multiple google accounts

Is there any way to support a login flow for a user with multiple Google accounts when only one of them is authorized for our app?

E.g.

  1. User has Google accounts A and B, B is authorized for our app
  2. User is logged in as A
  3. User logins with Google to our app and under the hood we are using passport-google-oauth2
  4. User is recognised as A but A is not authorized for our app
  5. User needs to visit e.g. https://accounts.google.com/AccountChooser and logout A or login with B
  6. After clearing cookies (passport session) user can now try to login again to our app

We would like to make the flow more convenient for the user and without having to go to separate google page for switching account. Is there any way to force prompting user selection for example?

Not sure if this is a feature request or simply not understanding the library fully but any advice would be appreciated.

dynamic callbackURL

Hi,

Thank you for releasing an 'official' Google Oauth2 passport module. I am having some trouble trying to implement a dynamic callback URL arrangement similar to that discussed here:
jaredhanson/passport-facebook#2

I have two auth routes available, with two callback routes (which are also specified in my Google account):

    app.get('/auth/google', passport.authenticate('google', { scope: scope,
        accessType: 'offline'
    }));
    app.get('/auth/google/calendar', passport.authenticate('google', { scope: calendarScope,
        accessType: 'offline',
        callbackURL: '/auth/google/callback/calendar'
    }));

    app.get('/auth/google/callback', passport.authenticate( 'google', {
        successRedirect: '/dashboard',
        failureRedirect: '/'
    }));
    app.get('/auth/google/callback/calendar', passport.authenticate( 'google', {
        successRedirect: '/dashboard/applications?calendar=yes',
        failureRedirect: '/dashboard/applications?calendar=no'
    }));

But this does not work, no matter what combination of methods I try, I always receive the following error:

500

TokenError: Bad Request
    at Strategy.OAuth2Strategy.parseErrorResponse (/opt/.../node_modules/passport-oauth2/lib/strategy.js:320:12)
    at Strategy.OAuth2Strategy._createOAuthError (/opt/.../node_modules/passport-oauth2/lib/strategy.js:367:16)
    at /opt/.../node_modules/passport-oauth2/lib/strategy.js:166:45
    at /opt/.../node_modules/oauth/lib/oauth2.js:177:18
    at passBackControl (/opt/.../node_modules/oauth/lib/oauth2.js:123:9)
    at IncomingMessage.<anonymous> (/opt/.../node_modules/oauth/lib/oauth2.js:143:7)
    at emitNone (events.js:85:20)
    at IncomingMessage.emit (events.js:179:7)
    at endReadableNT (_stream_readable.js:913:12)
    at _combinedTickCallback (internal/process/next_tick.js:74:11)
    at process._tickCallback (internal/process/next_tick.js:98:9)

Refresh token undefined

I'm using passport to oAuth with google. In my callback after the user has logged in, although the parameters are: (accessToken, refreshToken, profile, done), the refreshToken is undefined while every other parameter is what it should be. Am I using the library incorrectly?

I am using the below library to define my google strategy:

'require('passport-google-oauth').OAuth2Strategy'

Issue with google id token

Hi,

I am using below API

app.get('/auth/google', passport.authenticate('google', { scope: ['profile', 'email'] }));

I am getting the id token from google but when I am using the same id token in below API

https://oauth2.googleapis.com/tokeninfo?id_token=<ID_TOKEN>

I am not receiving the profile data. but when I am using the access token I am getting the profile data. issues seems to have only with id token

Error on callback route with passport `Error at Strategy.OAuth2Strategy.parseErrorResponse`

Error at Strategy.OAuth2Strategy.parseErrorResponse (E:\Programowanie\NodeJS\Hydronide\node_modules\passport-oauth2\lib\strategy.js:329:12) at Strategy.OAuth2Strategy._createOAuthError (E:\Programowanie\NodeJS\Hydronide\node_modules\passport-oauth2\lib\strategy.js:376:16) at E:\Programowanie\NodeJS\Hydronide\node_modules\passport-oauth2\lib\strategy.js:166:45 at E:\Programowanie\NodeJS\Hydronide\node_modules\oauth\lib\oauth2.js:191:18 at passBackControl (E:\Programowanie\NodeJS\Hydronide\node_modules\oauth\lib\oauth2.js:132:9) at IncomingMessage.<anonymous> (E:\Programowanie\NodeJS\Hydronide\node_modules\oauth\lib\oauth2.js:157:7) at emitNone (events.js:110:20) at IncomingMessage.emit (events.js:207:7) at endReadableNT (_stream_readable.js:1059:12) at _combinedTickCallback (internal/process/next_tick.js:138:11) at process._tickCallback (internal/process/next_tick.js:180:9)

Stackoverflow question

passBackControl errors

Error
    at /Users/theonlygusti/Project/node_modules/passport-google-oauth20/lib/strategy.js:95:21
    at passBackControl (/Users/theonlygusti/Project/node_modules/oauth/lib/oauth2.js:132:9)
    at IncomingMessage.<anonymous> (/Users/theonlygusti/Project/node_modules/oauth/lib/oauth2.js:157:7)
    at emitNone (events.js:91:20)
    at IncomingMessage.emit (events.js:185:7)
    at endReadableNT (_stream_readable.js:974:12)
    at _combinedTickCallback (internal/process/next_tick.js:74:11)
    at process._tickCallback (internal/process/next_tick.js:98:9)

I get the above error after: going to /sign-in/go, clicking my google account from the list google gives me, then ... error (url looks like http://localhost:61337/sign-in/after?code=4/BIsK3AIVt0p-Lk5ZGsyVqrv3KG3FevvO_ZPeKTwF6Tm# at this stage.)

Here's my code:

const express=require('express');
const app = express();
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;

passport.use(new GoogleStrategy({
  clientID: process.env.GOOGLE_OAUTH_CLIENT_ID,
  clientSecret: process.env.GOOGLE_OAUTH_CLIENT_SECRET,
  callbackURL: '/sign-in/after'
},
function(accessToken, refreshToken, profile, cb) {
  User.findOrCreate({ googleId: profile.id }, function (err, user) {
    return cb(err, user);
  });
}));

app.get('/sign-in/go', passport.authenticate('google', { scope: ['profile'] }));

app.get('/sign-in/after',
  passport.authenticate('google', { failureRedirect: '/sign-in' }),
  function(req, res) {
    // Successful authentication, redirect home.
    res.redirect('/');
  });

const httpServer = app.listen(app.get('port'));

TokenStrategy is not a constructor

Looks like passport-google-token is having some trouble registering.

 express:router:route delete /auth/google/:__feathersId +0ms
  express:router:layer new / +0ms
  express:router:route delete /auth/google/:__feathersId +0ms
  express:router:layer new / +0ms
  express:router:route delete /auth/google/:__feathersId +0ms
  express:router:layer new / +0ms
  feathers-authentication:oauth2 registering passport-google OAuth2 strategy +1ms
  feathers-authentication:oauth2 registering passport-google-token OAuth2 strategy +1ms
/Users/lawrencebolutife/Documents/kunibooks_api/node_modules/feathers-authentication/lib/services/oauth2.js:49
      _passport2.default.use(new TokenStrategy(options, service.oauthCallback.bind(service)));
                             ^

TypeError: TokenStrategy is not a constructor

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.