Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passport - Node.js not returning Refresh Token

Tags:

I am trying to return a refreshToken using the passport module of node.js. However I am using the code below and I am unable to log any refresh token but the access token works fine. Is there any way to specify the access-type offline for this module to hopefully return this?

var GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;  passport.use(new GoogleStrategy({  clientID: GOOGLE_CLIENT_ID,  clientSecret: GOOGLE_CLIENT_SECRET,  callbackURL: "http://myurl/auth/callback"  },  function(accessToken, refreshToken, profile, done) {                                                               console.log(refreshToken);   process.nextTick(function () {       return done(null, [{token:accessToken}, {rToken:refreshToken}, {profile:profile}]);   }); } )); 

This returns the refreshToken as undefined.

Any help would be greatly appreciated.

like image 710
MonsterWimp757 Avatar asked Feb 21 '14 18:02

MonsterWimp757


2 Answers

This was solved with this link:

https://github.com/jaredhanson/passport/issues/42

specifically:

passport.authenticate('google', { scope: ['https://www.googleapis.com/auth/userinfo.profile',                                       'https://www.googleapis.com/auth/userinfo.email'],                                       accessType: 'offline', approvalPrompt: 'force' }); 

Jared Hanson - bless you.

like image 68
MonsterWimp757 Avatar answered Sep 20 '22 08:09

MonsterWimp757


All you need is accessType: 'offline' and you'll get the refreshToken on first login.

You don't need approvalPrompt or prompt in the request.

Note this only works on first login if you don't capture and save the refreshToken and associate it with a user account on first login you can't easily get it again.

If you didn't capture it the first time someone logs in, then you have two options:

  1. If a user logs in and you don't have a refreshToken for them, you can immediately forceably log them out (e.g. by expiring their session in your app) and tell them to go to https://myaccount.google.com/permissions and revoke access to your application then just sign in again.

When they sign in again they will get the same prompt for access they got on first login and you will get the refreshToken on that first new login. Just be sure to have a method in your callback in Passport to save the refreshToken to their user profile in your database.

You can then use the refreshToken to request a rotating accessToken whenever you need to call a Google API.

  1. You could also add both accessType: 'offline' and prompt: 'consent' options, but this is probably not what you want in a web based application.

Using these will prompt every user to approve access to your app every time they sign in. Despite the name, approvalPrompt does not enforce this, at least not in the current version of the API (judging by the number of people mentioning it and how often oAuth APIs change it's entirely possible this behavior used to be different).

This isn't a great approach for web based apps as it's not a great user experience but might be useful for development/debugging.

More about the second option:

This option is intended for scenarios such as mobile or desktop apps where the tokens will persist locally (not in a browser, where they are much more likely to be cleared when cache is cleared or they naturally expire).

Google limit how many refresh tokens they will issue for a user on an application (and they will invalidate the oldest tokens automatically and silently) so it's generally a bad idea to use this approach for a web app, as users might find they end up getting signed out of other browser sessions.

like image 21
Iain Collins Avatar answered Sep 19 '22 08:09

Iain Collins