How to use an existing access token to authenticate against the Google API in Ruby

After a few hours of trial and error and finally getting authentication against Google’s API working in Ruby I think it’s time for a blog post 😉

I had a simple (at least I thought it was simple) requirement: Reading the people in a user’s Google+ circles with Ruby. Because I use OmniAuth in my application, the user is already authenticated and I even have his access token stored in the database. However, it took me a few hours to find out how to use this token to access Google’s API.

Reading people from a Google+ user’s circles

Reading the people from a user’s circle is quite easy. Simply use plus.people.list. You can try it with the Google APIs Explorer. However, you need to make sure, your app requests the right permissions. This is the corresponding line from my Rails initializer omniauth.rb (I needed to add the scope plus.login and change the access type to offline):

provider :google_oauth2, "CLIENTID", "SECRET", scope: 'profile,email,plus.login', image_aspect_ratio: 'square', image_size: 48, access_type: 'offline', name: 'google'

The Ruby code using google-api-ruby-client looks like this:

plus = Google::Apis::PlusV1::PlusService.new
friends = plus.list_people("me", "visible").items

The items you get from Google+ look like this:

#<Google::Apis::PlusV1::Person:0x4307fd0 
    @display_name="The Name",
    @etag="\some tag\"",
    @id="1234",
    @image=#<Google::Apis::PlusV1::Person::Image:0x43057f8 
        @url="https://lh6.googleusercontent.com/.../photo.jpg?sz=50">,
    @kind="plus#person",
    @object_type="person",
    @url="https://plus.google.com/1234">

Using an existing access token for authentication

Google’s documentation states that you need to use Signet to authenticate against the Google API. So I thought I’d give it a try and started coding. But as it turns out, Signet is a complex beast and I didn’t want to re-implement the whole OAuth authentication process, because OmniAuth already does that for me. I just wanted to use my existing token for authentication!

Long story short: I found the solution in file http_command.rb in method apply_request_options():

if options.authorization.respond_to?(:apply!)
    options.authorization.apply!(req.header)
elsif options.authorization.is_a?(String)
   req.header[:authorization] = sprintf('Bearer %s', options.authorization)
end

You can simply set the attribute authorization of your PlusService to a string (instead of a Signet object) and it will be set as the Bearer in the HTTP request to Google’s API. So, I simply had to add this line to my calling code and I was done:

plus.authorization = access_token

The final code

I still can’t believe that the final solution is so simple! 🙂

Gemfile:

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

omniauth.rb:

provider :google_oauth2, "CLIENTID", "SECRET", scope: 'profile,email,plus.login', image_aspect_ratio: 'square', image_size: 48, access_type: 'offline', name: 'google'

friend_reader.rb:

require 'google/apis/plus_v1'

plus = Google::Apis::PlusV1::PlusService.new
plus.authorization = access_token
friends = plus.list_people("me", "visible").items

1 thought on “How to use an existing access token to authenticate against the Google API in Ruby”

Leave a Comment

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax