Search code examples
ruby-on-railsrubygoogle-authenticationgoogle-api-ruby-client

How to set the Google API user to impersonate using a Service Account (Ruby Client)?


I have a service account and I am using the OAuth2 gem together with the Google API Ruby Client:

require 'oauth2'
require 'google/api_client'

My objective is to fetch an access token which allows access to a specific user’s account and no other. I think this is often achieved using the sub parameter when using HTTP, but how do I do this using the Ruby client libraries above?

I can get an access token successfully and use it to access the drive v2 file list API. I always see a single "How to get started with Drive" document in the response and no other.

I suspect my attempt to impersonate a user has not succeeded. Basically I’m passing in an email address as a sub option to the function below:

client = Google::APIClient.new(...)
access_token = OAuth2::AccessToken.new(oauth2_client, client.authorization.access_token, {‘sub’ => ‘[email protected]’} )

Presumably that isn’t the way to do this.

How to I retrieve an access token which is scoped to permit access impersonating a single user and no other?


Following Steve's comment I have dropped the intridea Gem and am now using Signet. I get a little further but I am stuck getting an access_denied error when I specify a :person. Without that I can authenticate but obviously I get access as the issuer.

require 'google/api_client'
...
client = Google::APIClient.new(:application_name => application_name, :application_version => application_version)
...
opts = {
  :token_credential_uri => 'https://accounts.google.com/o/oauth2/token',
  :audience => 'https://accounts.google.com/o/oauth2/token',
  :scope => scope,
  :issuer => service_account_email_address,
  :signing_key => key,
  :person => '[email protected]'
})
client.authorization = Signet::OAuth2::Client.new(opts)
access_token = client.authorization.fetch_access_token!
...

>> client.authorization.fetch_access_token!
Signet::AuthorizationError: Authorization failed.  Server message:
{
  "error" : "access_denied",
  "error_description" : "Requested client not authorized."
}

I have a console project which I do a 'test install flow' on but the client does not seem to be trusted. Where do I look?

Thanks.


Solution

  • Here's the summary.

    Do not use the OAuth2 gem from intridea if you are only trying to authenticate with Google. Rely on the signet Gem.

    If you use a service account, you can specify a :person element and it will work so you impersonate that user and work on their behalf.

    When you test your integration you must do so against the domain in which your project is hosted. You cannot test in a third-party domain until you've published your app!