How can I use Google default credentials on Heroku without the JSON file?

Solution 1:

When using the google translation api, I ran into the same issue. I was unable to reference the whole JSON file, so I created two env variables in Heroku and referenced them in a credentials object. You can not have them stand alone. The .replace for the private key is an important detail. You should paste in that full key as is on Heroku.

const Translate = require('@google-cloud/translate');
const projectId = 'your project id here';

const translate = new Translate({
  projectId: projectId,
  credentials: {
    private_key: process.env.GOOGLE_PRIVATE_KEY.replace(/\\n/g, '\n'),
    client_email: process.env.GOOGLE_CLIENT_EMAIL
  }
});

Solution 2:

The getApplicationDefault method is really just a convenience factory for finding the right client. You can actually construct your client directly, passing in the parameters read from environmental variables defined in Heroku.

Take this example which I used recently with a Heroku deployment:

const GoogleAuth = require('google-auth-library');

function authorize() {
    return new Promise(resolve => {
        const authFactory = new GoogleAuth();
        const jwtClient = new authFactory.JWT(
            process.env.GOOGLE_CLIENT_EMAIL, // defined in Heroku
            null,
            process.env.GOOGLE_PRIVATE_KEY, // defined in Heroku
            ['https://www.googleapis.com/auth/calendar']
        );

        jwtClient.authorize(() => resolve(jwtClient));
    });
}

Solution 3:

thanks! i also found another solution in case it helps others:

// Authenticating on a global basis. var projectId = process.env.GCLOUD_PROJECT; // E.g. 'grape-spaceship-123'

var gcloud = require('google-cloud')({ projectId: projectId,

credentials: require('./path/to/keyfile.json')

});

this way you can deconstruct the entire json key provided by auth

Solution 4:

I was just dealing with the same issue and couldn't find a solution online that I could get to work, so I made my own. I know this is an old issue, but wanted to share, so others might find it down the road.

To solve this problem, I used Node JS to programmatically write the file to the host after deployment by accessing the secret key values in my environment variables.

First, I created an object to behave as a JSON template in my JS code with the correct key names and used my environment variables to get the key values in that object. With that template in place, I was almost ready to have Node write the file to the host,, but I had one issue to solve.

I discovered from another post that JSON.stringify() will modify any backslash ('') that comes from an environment variable into two backslashes ('\') (it will not make this change when a backslash comes from a string in a JavaScript object). This was a problem for me because my private key had 28 backslashes. To correct this, as documented in the link above, I retrieved the value of the environment variable and updated the object before passing the object through JSON.stringify().

With that issue solved, I was able to write the file to the host and successfully deploy my app without exposing my JSON file on my public repository.

const fs = require('fs');

async function createJSONFile() {

  //Replace '\' in environment variable .env file before JSON.stringify() 
  //so that stringify does not turn it into '\\'
  //https://stackoverflow.com/a/36439803/13604562
  jsonFile.private_key = process.env.GCS_JSON_private_key.replace(/\\n/g, '\n');

  let data = JSON.stringify(jsonFile);
  //CHECK IF JSON KEYFILE FOR GCS EXISTS. IF NOT, CREATES FILE
  if (!fs.existsSync(`./${process.env.GCS_KEYFILE}`)) {
    await fs.writeFile(`./${process.env.GCS_KEYFILE}`, data, function (err) {
      if (err) {
        return res.status(400).json(err);
      }
    });
  }
}

//JSON file template
let jsonFile = {
  type: `${process.env.GCS_JSON_type}`,
  project_id: `${process.env.GCS_JSON_project_id}`,
  private_key_id: `${process.env.GCS_JSON_private_key_id}`,
  private_key: `${process.env.GCS_JSON_private_key}`,
  client_email: `${process.env.GCS_JSON_client_email}`,
  client_id: `${process.env.GCS_JSON_client_id}`,
  auth_uri: `${process.env.GCS_JSON_auth_uri}`,
  token_uri: `${process.env.GCS_JSON_token_uri}`,
  auth_provider_x509_cert_url: `${process.env.GCS_JSON_auth_provider_x509_cert_url}`,
  client_x509_cert_url: `${process.env.GCS_JSON_client_x509_cert_url}`,
};

createJSONFile();