3
votes

I'm trying to get offline access with Google APIs. I have to pull data from Google Calendar without having the user sign-in everytime.

I've added this to my Gemfile:

gem 'google-api-client', '~> 0.9'

... And added this to my controller:

require 'google/api_client/client_secrets'
class Api::V1::CalendarAccountsController < Api::V1::BaseController
...

And in my action:

client_secrets = Google::APIClient::ClientSecrets.load(
  File.join(
    Rails.root,
    'config',
    'client_secrets.json')
  )

@auth_client = client_secrets.to_authorization

@auth_client.update!(
    :scope => 'https://www.googleapis.com/auth/calendar.readonly',
    :redirect_uri => '/{callback URL}',

    :additional_parameters => {
      "access_type" => "offline",
      "include_granted_scopes" => "true"
    }
)
redirect_to @auth_client.authorization_uri.to_s

The problem is -- even though I'm specifying "access_type" as "offline", I still don't get asked for offline-access privileges in the Google privileges list (I'm attaching a screenie below).

And here's the page Google loads (no offline-access): Google privileges list with no offline-access request

And here's the URL that got generated when I called @auth_client.authorization_uri.to_s

https://accounts.google.com/o/oauth2/auth?access_type=offline&client_id=[ID]&redirect_uri=[callback]&response_type=code&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcalendar.readonly&from_login=1&as=-23788065e9c098d9&pli=1&authuser=0

Am I missing something?

2

2 Answers

1
votes

Try adding this code. If your application needs offline access to a Google API, set the API client's access type to offline:

auth_client.update!(
  :additional_parameters => {"access_type" => "offline"}
)

After a user grants offline access to the requested scopes, you can continue to use the API client to access Google APIs on the user's behalf when the user is offline. The client object will refresh the access token as needed.

Also use the Google client library, this will help you with refreshing an access token (offline access).

Hope this helps.

1
votes

You can try using something like this:

client = Signet::OAuth2::Client.new({
  client_id: your_client_id,
  client_secret: your_secret_id,
  authorization_uri: 'https://accounts.google.com/o/oauth2/auth',
  scope: Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY,
  redirect_uri: your_callback_url
})

client.update!(
  additional_parameters: {
    access_type: 'offline',
    prompt: 'consent'
  }
)

redirect_to client.authorization_uri.to_s

Note that I am using a more recent version of the google-api-client gem, configured this way:

gem 'google-api-client', '~> 0.11', require: 'google/apis/calendar_v3'

This way Google will ask you for permission to interact with the Calendar API and correctly setting the access_type parameter to grant you offline access to the same APIs.

This approach will prompt the user for the authorization each time you call the code. If you want to prevent this, you have to change it this way:

client.update!(
  additional_parameters: {
    access_type: 'offline'
  }
)

If you have already authorized your app without the access_type: 'offline' parameter Google will grant you an authentication token without the offline permits. To reset this situation it is sufficient to go into your Google profile permissions and revoke the previous authorization for your application. Then try again.

(Note: the signet gem is a dependency of googleauth, which in turn is a dependency of google-api-client, so you get this code for free, without the need to add more gems to the Gemfile)