How can I authorize a Google Service Account without the default credentials file?
Asked Answered
B

4

17

I have a Google Service Account that my app uses to retrieve data from Google Analytics.

When I created the account I downloaded a client_secrets file with all the necessary information for authorization via OAuth, and I recorded the path to this file in an environment variable called GOOGLE_APPLICATION_CREDENTIALS as per Google's documentation.

I can now get an authenticated client like this:

authorization = Google::Auth.get_application_default(scopes) 

This method reads the credentials out of the file, which works locally, but my app is hosted on Heroku where file storage is impossible.

The documentation states that I can either provide this file (can’t), run my app on an official Google Service (won’t), or experience an error.

How can I authenticate my service account without the client_secrets file?

Bounded answered 10/3, 2016 at 23:51 Comment(0)
B
27

I found the answer in the source code of the google-auth-library-ruby gem.

It turns out that there is another option: take the values from the client_secrets file and put them in environment variables named GOOGLE_ACCOUNT_TYPE, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_EMAIL and GOOGLE_PRIVATE_KEY respectively.

If these keys are populated, the credentials will load from there. Not a whisper of this in the docs, though.

Bounded answered 10/3, 2016 at 23:51 Comment(1)
More info in the docs now: github.com/googleapis/…Qualifier
I
8

Since this is one of the main results that returns when searching google for "google service credentials ruby," I thought I would add my very recent experience to the list of possible answers.

Though you can do the method mentioned in the first answer, I found an alternate solution that works well with Heroku. I know it has been somewhat mentioned in another post, but the key thing that was left out was how to properly store the full GOOGLE_APPLICATION_CREDENTIALS .json file so that it can all be kept within one env on Heroku and not have special characters blow up your app when tryin to

I detail my steps below:

  1. Obtain your GOOGLE_APPLICATION_CREDENTIALS json file by following Google's instructions here: Getting Started with Authentication
  2. That will, of course, contain a json object with all the spaces, line returns, and quotations that heroku simply doesn't need. So, strip out all spaces and line breaks...AND PAY ATTENTION HERE -> EXCEPT FOR THE LINE BREAKS WITHIN THE 'BEGIN PRIVATE KEY' SEGMENT. Basically turn the json into one long string. Use whatever method you feel comfortable with.
  3. Once you have a single line json file with whitespace and line breaks removed, you will need to add it to Heroku by running the following command:

    heroku config:set GOOGLE_APPLICATION_CREDENTIALS="$(< /Users/whoever/Downloads/[CREDENTIAL_JSON_FILENAME].json)" --app your-app
    
  4. For my situation, I needed to have the service account available on initialization, so I placed this in an initializer in my rails app:

    GOOGLE_SERVICE_ACCOUNT_CREDENTIALS=Google::Auth::ServiceAccountCredentials.make_creds(
      json_key_io: StringIO.new(ENV['GOOGLE_APPLICATION_CREDENTIALS'])
    )
    

Notice the StringIO.new() method. the #make_creds wants a file. So, fake it as such by using StringIO.new.

This method works perfectly.

If you need this to work differently on your local machine, you can always store the .json somewhere in the project and reference it through a file location string. Here is my full initializer:

require 'googleauth'

#https://www.rubydoc.info/github/google/google-auth-library-ruby/Google/Auth/ServiceAccountCredentials 
if Rails.env == "test"
  GOOGLE_SERVICE_ACCOUNT_CREDENTIALS = 
Google::Auth::ServiceAccountCredentials.make_creds(
    json_key_io: File.open('lib/google/google_application_credentials.json')
  ) 
elsif Rails.env != "development"
    GOOGLE_SERVICE_ACCOUNT_CREDENTIALS = 
Google::Auth::ServiceAccountCredentials.make_creds(
    json_key_io: StringIO.new(ENV['GOOGLE_APPLICATION_CREDENTIALS'])
  ) 
end

If you are using a gem like dotenv you can store the formatted json string as an ENV or you can just reference the file location in the ENV

I hope this helps someone.

Inelastic answered 15/6, 2018 at 19:55 Comment(2)
If you are fetching a service account token using this method, do it like this: authorizer = Google::Auth::ServiceAccountCredentials.make_creds(json_key_io: StringIO.new(ENV['GOOGLE_APPLICATION_CREDENTIALS']), scope: "https://www.googleapis.com/auth/firebase.messaging") authorizer.fetch_access_token! from the googleauth docsAdriatic
@JeppeLiisberg - Good point. I didn't really address the OP's authorization portion. Thanks for that clarification.Inelastic
H
0

If running app in cluster in Google Kubernetes Engine (GKE), then answer is

https://googleapis.dev/ruby/googleauth/latest/Google/Auth/GCECredentials.html

authorizer = Google::Auth::GCECredentials.new(target_audience:)
token = authorizer.fetch_access_token["id_token"]

# header
# "Authorization": "Bearer #{token}"

Just noting this down, since this answer was one of the top results what I got when trying to figure out how to make it work.

Hassan answered 6/5 at 10:57 Comment(0)
E
-2

I found this

require "google/cloud/bigquery"

ENV["BIGQUERY_PROJECT"]     = "my-project-id"
ENV["BIGQUERY_CREDENTIALS"] = "path/to/keyfile.json"

bigquery = Google::Cloud::Bigquery.new

more detail:

https://github.com/googleapis/google-cloud-ruby/blob/master/google-cloud-bigquery/AUTHENTICATION.md

Ethelyn answered 25/2, 2020 at 9:14 Comment(1)
This does not avoid the need for the .json file.Lanti

© 2022 - 2024 — McMap. All rights reserved.