Meteor accounts-google Token Expires

I have the Accounts-UI config setup to store an offline token for google thusly:

if (Meteor.isClient) {
 Accounts.ui.config({
  requestOfflineToken: { google: true },
  forceApprovalPrompt: { google: true },
  requestPermissions: { google: ["https://mail.google.com/"] }
 });
}

However, tokens seem to expire. I assume I need to somehow use the refreshToken. I'm not sure how though with meteor. Any help would be lovely. Thanks!

Answers:

Answer

I recommend using Google API Node JS client to refresh your access tokens.

https://github.com/google/google-api-nodejs-client/

It's available as a server-side NPM package, so you might want to use this package to be able to npmRequire it in your Meteor app.

Use this packages.json config to load the latest googleapis package :

{
  "googleapis": "2.1.5"
}

Then in your Meteor server code you'll be able to refresh the access tokens like this :

ES2015

const GoogleApis = Meteor.npmRequire('googleapis');

function getAccessToken(user) {
  const googleService = user.services.google;
  // is token still valid for the next minute ?
  if (googleService.expiresAt < Date.now() + 60 * 1000) {
    // then just return the currently stored token
    return {
      access_token: googleService.accessToken,
      token_type: 'Bearer',
      id_token: googleService.idToken,
      expiry_date: googleService.expiresAt,
      refresh_token: googleService.refreshToken,
    };
  }
  // fetch google service configuration
  const googleServiceConfig = Accounts.loginServiceConfiguration.findOne({
    service: 'google',
  });
  // declare an Oauth2 client
  const oauth2Client = new GoogleApis.auth.OAuth2(googleServiceConfig.clientId, googleServiceConfig.secret);
  // set the Oauth2 client credentials from the user refresh token
  oauth2Client.setCredentials({
    refresh_token: user.services.google.refreshToken,
  });
  // declare a synchronous version of the oauth2Client method refreshing access tokens
  const refreshAccessTokenSync = Meteor.wrapAsync(oauth2Client.refreshAccessToken, oauth2Client);
  // refresh tokens
  const tokens = refreshAccessTokenSync();
  // update the user document with the fresh token
  Meteor.users.update(user._id, {
    $set: {
      'services.google.accessToken': tokens.access_token,
      'services.google.idToken': tokens.id_token,
      'services.google.expiresAt': tokens.expiry_date,
      'services.google.refreshToken': tokens.refresh_token,
    },
  });
  //
  return tokens;
}

Here is a full example of how to refresh your access tokens before using a google service.

function listMeteorChannel() {
  // fetch a user you want to act on behalf who authorized offline access
  const user = Meteor.users.findOne({
    'services.google.refreshToken': {
      $exists: true,
    },
  });
  if (!user) {
    return;
  }
  const googleServiceConfig = Accounts.loginServiceConfiguration.findOne({
    service: 'google',
  });
  // declare oauth2 client and set credentials
  const oauth2Client = new GoogleApis.auth.OAuth2(googleServiceConfig.clientId, googleServiceConfig.secret);
  // get user access token
  const tokens = getAccessToken(user);
  oauth2Client.setCredentials(tokens);
  // obtain the youtube service at version 3 and perform authentication at service level
  const youtube = GoogleApis.youtube({
    version: 'v3',
    auth: oauth2Client,
  });
  // declare a synchronous version of youtube.channels.list
  const youtubeChannelsListSync = Meteor.wrapAsync(youtube.channels.list, youtube.channels);
  // fetch an info snippet from the Meteor official YouTube channel
  const result = youtubeChannelsListSync({
    part: 'snippet',
    // Meteor channel ID
    id: 'UC3fBiJrFFMhKlsWM46AsAYw',
  });
  result.items.forEach((item) => {
    // display the channel title, which should be 'Meteor'
    console.log(item.snippet.title);
  });
}

Meteor.startup(listMeteorChannel);

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.