Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Google API credentials json on Heroku?

I'm making an app using Google Calendar API, and planning to build it on Heroku.
I have a problem about authentication. Usually I use credential json file for that, but this time I don't want to upload it on Heroku for security reason.
How can I make authentiation on Heroku?

For now, I put my json to an env variable, and use oauth2client's from_json method.

def get_credentials():
    credentials_json = os.environ['GOOGLE_APPLICATION_CREDENTIALS']
    credentials = GoogleCredentials.from_json(credentials_json)
    if not credentials or credentials.invalid:
        flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
        flow.user_agent = APPLICATION_NAME
        if flags:
            credentials = tools.run_flow(flow, store, flags)
        else: # Needed only for compatibility with Python 2.6
            credentials = tools.run(flow, store)
        print('Storing credentials to ' + credential_path)
    return credentials 

But this code isn't perfect. If the credentials is invalid, I want the code to write the new credentials to the env variable, not to a new file.
Is there any better way?

like image 482
lipsum Avatar asked Nov 23 '17 02:11

lipsum


4 Answers

I spent an entire day to find the solution because it's tricky. No matter your language, the solution will be the same.

1 - Declare your env variables from in Heroku dashboard like :

The GOOGLE_CREDENTIALS variable is the content of service account credential JSON file as is. The GOOGLE_APPLICATION_CREDENTIALS env variable in the string "google-credentials.json"

2 - Once variables are declared, add the builpack from command line :

$ heroku buildpacks:add https://github.com/elishaterada/heroku-google-application-credentials-buildpack

3 - Make a push. Update a tiny thing and push.

4 - The buildpack will automatically generate a google-credentials.json and fill it with the content of the google credentials content.

If you failed at something, it will not work. Check the content of the google-credentials.json with the Heroku bash.

like image 88
Maxime Boué Avatar answered Oct 10 '22 12:10

Maxime Boué


The buildpack mentioned by Maxime Boué is not working anymore because of the Heroku updates(18+). However, below is a similar buildpack which is working. It is actually a fork from the previous one.

  • Use the below link in the buildpack setting of your Heroku app settings https://github.com/gerywahyunugraha/heroku-google-application-credentials-buildpack
  • Define in Config Vars GOOGLE_CREDENTIALS as key and content of your credential file as Value
  • Define in Config Vars GOOGLE_APPLICATION_CREDENTIALS as Key and google-credentials.json as Value
  • Redeploy the application, it should work!!
like image 22
sam Avatar answered Oct 10 '22 11:10

sam


If anyone is still looking for this, I've just managed to get this working for Google Cloud Storage by storing the JSON directly in an env variable (no extra buildpacks).

You'll need to place the json credentials data into your env vars and install google-auth

Then, parse the json and pass google credentials to the storage client:

from google.cloud import storage
from google.oauth2 import service_account

# the json credentials stored as env variable
json_str = os.environ.get('GOOGLE_APPLICATION_CREDENTIALS')
# project name
gcp_project = os.environ.get('GCP_PROJECT') 

# generate json - if there are errors here remove newlines in .env
json_data = json.loads(json_str)
# the private_key needs to replace \n parsed as string literal with escaped newlines
json_data['private_key'] = json_data['private_key'].replace('\\n', '\n')

# use service_account to generate credentials object
credentials = service_account.Credentials.from_service_account_info(
    json_data)

# pass credentials AND project name to new client object (did not work wihout project name)
storage_client = storage.Client(
    project=gcp_project, credentials=credentials)

Hope this helps!

EDIT: Clarified that this was for Google Cloud Storage. These classes will differ for other services, but from the looks of other docs the different Google Client classes should allow the passing of credentials objects.

like image 11
Tom Avatar answered Oct 10 '22 10:10

Tom


The recommended buildpack doesn't work anymore. Here's a quick, direct way to do the same:

  1. Set config variables:
heroku config:set GOOGLE_APPLICATION_CREDENTIALS=gcp_key.json
heroku config:set GOOGLE_CREDENTIALS=<CONTENTS OF YOU GCP KEY>

The GOOGLE_CREDENTIALS is easier to set in the Heroku dashboard.

  1. Create a .profile file in your repo with a line to write the json file:
echo ${GOOGLE_CREDENTIALS} > /app/gcp_key.json

.profile is run every time the container starts.

  1. Obviously, commit the changes to .profile and push to Heroku, which will trigger a rebuild and thus create that gcp_key.json file.

like image 10
Chrisjan Avatar answered Oct 10 '22 12:10

Chrisjan