diff --git a/packages/accounts-google/google_client.js b/packages/accounts-google/google_client.js index c01801c45a..6c7542ce64 100644 --- a/packages/accounts-google/google_client.js +++ b/packages/accounts-google/google_client.js @@ -19,18 +19,22 @@ var scope = ['https://www.googleapis.com/auth/userinfo.email']; if (options && options.requestPermissions) scope = options.requestPermissions; - // Might be good to have a way to set access_type=offline. Need to - // both set it here and store the refresh token on the server. scope = _.union(scope, requiredScope); var flatScope = _.map(scope, encodeURIComponent).join('+'); + var accessType = config.accessType; + if (!accessType) { + accessType = 'online'; + } + var loginUrl = 'https://accounts.google.com/o/oauth2/auth' + '?response_type=code' + '&client_id=' + config.clientId + '&scope=' + flatScope + '&redirect_uri=' + Meteor.absoluteUrl('_oauth/google?close') + - '&state=' + state; + '&state=' + state + + '&access_type=' + accessType; Accounts.oauth.initiateLogin(state, loginUrl, callback); }; diff --git a/packages/accounts-google/google_configure.js b/packages/accounts-google/google_configure.js index c5740c6c9f..f9de471f2b 100644 --- a/packages/accounts-google/google_configure.js +++ b/packages/accounts-google/google_configure.js @@ -5,6 +5,7 @@ Template.configureLoginServiceDialogForGoogle.siteUrl = function () { Template.configureLoginServiceDialogForGoogle.fields = function () { return [ {property: 'clientId', label: 'Client ID'}, - {property: 'secret', label: 'Client secret'} + {property: 'secret', label: 'Client secret'}, + {property: 'accessType', label: 'Access type (online or offline)'} ]; -}; \ No newline at end of file +}; diff --git a/packages/accounts-google/google_server.js b/packages/accounts-google/google_server.js index 167e5f1b75..33568c6598 100644 --- a/packages/accounts-google/google_server.js +++ b/packages/accounts-google/google_server.js @@ -2,17 +2,27 @@ Accounts.oauth.registerService('google', 2, function(query) { - var accessToken = getAccessToken(query); + var response = getAccessToken(query); + var accessToken = response.access_token; + var refreshToken = response.refresh_token; var identity = getIdentity(accessToken); + if (!refreshToken) { + + // Not all responses will include a refresh token, and we don't want to override an existing one with a null + // value if we actually already have one. + refreshToken = getRefreshToken(identity.id); + } + return { - serviceData: { - id: identity.id, - accessToken: accessToken, - email: identity.email - }, - options: {profile: {name: identity.name}} - }; + serviceData: { + id: identity.id, + accessToken: accessToken, + refreshToken: refreshToken, + email: identity.email + }, + options: {profile: {name: identity.name}} + }; }); var getAccessToken = function (query) { @@ -33,9 +43,17 @@ throw result.error; if (result.data.error) // if the http response was a json object with an error attribute throw result.data; - return result.data.access_token; + return result.data; }; + var getRefreshToken = function (id) { + var user = Meteor.users.findOne({'services.google.id': id}); + if (!user) + return null; + + return user.services.google.refreshToken; + }; + var getIdentity = function (accessToken) { var result = Meteor.http.get( "https://www.googleapis.com/oauth2/v1/userinfo",