9

I am using Google Speech API in my Django web-app. I have set up a service account for it and am able to make API calls locally. I have pointed the local GOOGLE_APPLICATION_CREDENTIALS environment variable to the service account's json file which contains all the credentials.

This is the snapshot of my Service Account's json file: enter image description here

I have tried setting heroku's GOOGLE_APPLICATION_CREDENTIALS environment variable by running

$ heroku config:set GOOGLE_APPLICATION_CREDENTIALS="$(< myProjCreds.json)"

$ heroku config
GOOGLE_APPLICATION_CREDENTIALS: {

^^ It gets terminated at the first occurrence of " in the json file which is immediately after { and

$ heroku config:set GOOGLE_APPLICATION_CREDENTIALS='$(< myProjCreds.json)'

$ heroku config
GOOGLE_APPLICATION_CREDENTIALS: $(< myProjCreds.json)

^^ The command gets saved into the environment variable

I tried setting heroku's GOOGLE_APPLICATION_CREDENTIALS env variable to the content of service account's json file but it didn't work (because apparently the this variable's value needs to be an absolute path to the json file) . I found a method which authorizes a developer account without loading json accout rather using GOOGLE_ACCOUNT_TYPE, GOOGLE_CLIENT_EMAIL and GOOGLE_PRIVATE_KEY. Here is the GitHub discussion page for it.

I want something similar (or something different) for my Django web-app and I want to avoid uploading the json file to my Django web-app's directory (if possible) for security reasons.

hulkinBrain
  • 746
  • 8
  • 28
  • The easiest way would be to dump your data as json string, store it in heroku environment variables and refer [this](https://google-auth.readthedocs.io/en/latest/user-guide.html#service-account-private-key-files). – Deekshant Mar 02 '21 at 12:10

2 Answers2

3

Depending on which library you are using for communicating with Speach API you may use several approaches:

  1. You may serialize your JSON data using base64 or something similar and set resulting string as one environment variable. Than during you app boot you may decode this data and configure your client library appropriately.

  2. You may set each pair from credentials file as separate env variables and use them accordingly. Maybe library that you're using support authentication using GOOGLE_ACCOUNT_TYPE, GOOGLE_CLIENT_EMAIL and GOOGLE_PRIVATE_KEY similar to the ruby client that you're linking to.

EDIT: Assuming that you are using google official client library, you have several options for authenticating your requests, including that you are using (service account): https://googlecloudplatform.github.io/google-cloud-python/latest/core/auth.html You may save your credentials to the temp file and pass it's path to the Client object https://google-auth.readthedocs.io/en/latest/user-guide.html#service-account-private-key-files (but it seems to me that this is very hacky workaround). There is a couple of other auth options that you may use.

EDIT2: I've found one more link with the more robust approach http://codrspace.com/gargath/using-google-auth-apis-on-heroku/. There is ruby code, but you may do something similar in Python for sure.

bronislav
  • 782
  • 7
  • 27
  • **Reply for 1.** Even if I encode the JSON data using base64 and then during app boot decode it, the requirement for `GOOGLE_APPLICATION_CREDENTIALS` value is to be an absolute path and NOT JSON data. (I tried it, it didn't work) **Reply for 2.** I tried making separate environment variables for the `key`s in the file and set them to their respective values, this too didnt work. (I tried appending `GOOGLE` to all the key values but still it didn't work – hulkinBrain Feb 18 '18 at 18:29
  • @hulkinBrain What library are you using for communicating with API? Official python client? Which version? – bronislav Feb 18 '18 at 18:30
  • I meant file content only, sorry for the ambiguity. Still, the issue remains the same, after decoding the base64 content, I'll need to separate the variables and make them and configure the `GOOGLE_APPLICATION_CREDENTIALS`. I couldn't find the docs where the ruby-like alterative could be applied in a python based app or a Django app – hulkinBrain Feb 18 '18 at 18:34
  • I'm not using any authentication client explicitly. I installed the speech api using `pip install google-cloud-speech` and am using the default authentication as mentioned in the docs https://cloud.google.com/speech/docs/sync-recognize (which instructs the user to make an environment variable and point it to the json file) using `client = speech.SpeechClient()` command – hulkinBrain Feb 18 '18 at 18:42
  • Thanks for you suggestions, I went through the links given by you. The first one was pertaining to Client ID based but they all were pertaining to generating credentials using an OAuth client ID *(which unfortunately isn't supported by Cloud Speech API, only service account access is supported as of now)* **but the second link worked for me**. Yes, it seems like a hacky workaround since I had to upload the JSON file for the method to work. I am marking your answer as the solution since I don't see any other alternative for authentication. Thanks mate :D – hulkinBrain Feb 18 '18 at 20:02
  • @hulkinBrain I've edited my answer once more. Please check. – bronislav Feb 18 '18 at 20:15
  • 2
    Yes there exists a method `service_account.Credentials.from_service_account_info(cls=JSONfileContent, scopes=scopes)` where i can feed in the jsonFileContent *by using `json.loads()` on the b64encoded* string which can be fetched from the environment variable! This method returns the credentials which can then further be used. Thankyou so much for improving your answer, This method seems the best alternative to setting an environment variable. Cheers! Feel free to include this line of code in your answer :D – hulkinBrain Feb 19 '18 at 06:45
0

Let's say the filename is key.json First, copy the content of the key.json file and add it to the environment variable, let's say KEY_DATA.

Solution 1:

If my command to start the server is node app.js, I'll do echo $KEY_DATA > key.json && node app.js

This will create a key.json file with the data from KEY_DATA and then start the server.

Solution 2:

Save the data from KEY_DATA env variable in the some variable and then parse it to JSON, so you have the object which you can pass for authentication purposes.

Example in Node.js:

const data = process.env.KEY_DATA;
const dataObj = JSON.parse(data);
swarajpure
  • 29
  • 1