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?
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.
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:
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With