Search code examples
meteoroauth-2.0google-oauthmeteor-accounts

Meteor Google oAuth to refresh accessToken without re-login


This is my first post. I will try and be complete. I am creating a app in Meteor which uses google oAuth. I am using the following packages:

accounts-ui
accounts-google
service-configuration
google-config-ui

In my login.js I have:

Template.login.events({
  'click #googleLoginButton': function() {
    Meteor.loginWithGoogle(
      { requestPermissions: ['email', 'profile'],
      requestOfflineToken: 'true'
      }
     );
  }
});

I get the following in mongo:

db.users.find({}).pretty();
{
    "_id" : "9TjGEjEj4ocFhwHtS",
    "createdAt" : ISODate("2017-10-11T17:38:07.400Z"),
    "services" : {
        "google" : {
            "accessToken" : "ya29.-REDACTED-T9z",
            "idToken" : "eyJhbGcj-REDACTED-LTg",
            "scope" : [
                "https://www.googleapis.com/auth/userinfo.email",
                "https://www.googleapis.com/auth/userinfo.profile"
            ],
            "id" : "107113228066746203535",
            "email" : "[email protected]",
            "verified_email" : true,
            "name" : "XXX XXX",
            "given_name" : "XXX",
            "family_name" : "XXX",
            "picture" : "https://lh4.googleusercontent.com/.../photo.jpg",
            "locale" : "en",
            "gender" : "male",
            "refreshToken" : "1/HG-REDACTED-oLq0USutc"
        },
        "resume" : {
            "loginTokens" : [
                {
                    "when" : ISODate("2017-10-11T21:47:38.471Z"),
                    "hashedToken" : "2lmOK-REDACTED-ptAyDnWo="
                }
            ]
        }
    },
    "profile" : {
        "name" : "XXX XXX"
    }
}

In the Server/init.js I have: (I am passing the google project info via settings.json)

configureGoogle = function(config) {
    ServiceConfiguration.configurations.remove({
        service: "google"
    });

    ServiceConfiguration.configurations.insert({
        service: "google",
        clientId: googleConfig.clientId,
        secret: googleConfig.secret
    });
    return;
};

if (googleConfig) {
    console.log('Got settings for google', googleConfig)
    configureGoogle(googleConfig);
}

So things seem to be working. I can login / out and when I login I get new tokens. I use the accessToken for api calls in other places. The problem I have is that after a hour the token expires and the API calls start to fail.

I would like to refresh the accessToken just before it expires and cant seem to figure out how. I would also like to force a logout after 24 hours so the token does not refresh forever.

Any assistance if appreciated.


Solution

  • Update #1

    Thanks to Derek Brown below for pointing me in the right direction. That got me to looking for a meteor google api. I found this one: percolate:google-api

    and according to it doc it does what I was looking for:

    If the user's access token has expired, it will transparently call the exchangeRefreshToken method to get a new refresh token.

    I then ran into a error where the expiresAt Didnt exist in my mongodb and things were not working. I then found this post: Google-API which suggested:

    server/publish.js

    Meteor.publish(null, function() {
      return Meteor.users.find(this.userId, { fields: { 
        'services.google.accessToken': 1, 
        'services.google.expiresAt': 1 
      }});
    });
    

    I also made one change from code above: client/login.js

    Template.login.events({
      'click #googleLoginButton': function() {
        Meteor.loginWithGoogle(
          { requestPermissions: ['email', 'profile'],
          requestOfflineToken: 'true',
          forceApprovalPrompt: 'true' //<==== This is the change
          }
         );
      }
    });
    

    This added with no additional code changed this added the expiresAt and populated it.

    Im doing final testing now. I will update.