35

I am using Google Drive API with my Rails application. The API is working fine. I have the following client_secret.json file:

{
  "type": "service_account",
  "project_id": "gobirdie-landing-page",
  "private_key_id": "xxxxx",
  "private_key": "-----BEGIN PRIVATE KEY----- xxxxx -----END PRIVATE KEY-----\n",
  "client_email": "xxxxxxx@gobirdie-landing-page.iam.gserviceaccount.com",
  "client_id": "xxxxxxxxx",
  "auth_uri": "xxxxxx",
  "token_uri": "xxxxxxx": "xxxxxxxx": "xxxxxxxxx"
}

which is called in my controller

@session = GoogleDrive::Session.from_service_account_key("client_secret.json")

With this configuration no problem, I manage to use the API. However, I would like to store my JSON in the .env file like:

CLIENT_SECRET = "{
  "type": "service_account",
  "project_id": "gobirdie-landing-page",
  "private_key_id": "xxxxx",
  "private_key": "-----BEGIN PRIVATE KEY----- xxxxx -----END PRIVATE KEY-----\n",
  "client_email": "xxxxxxx@gobirdie-landing-page.iam.gserviceaccount.com",
  "client_id": "xxxxxxxxx",
  "auth_uri": "xxxxxx",
  "token_uri": "xxxxxxx": "xxxxxxxx": "xxxxxxxxx"
}" 

And call it in the controller in this way

@session = GoogleDrive::Session.from_service_account_key(ENV['CLIENT_SECRET'])

Or in this way

@session = GoogleDrive::Session.from_service_account_key(JSON.parse(ENV['CLIENT_SECRET']))

But neither methods are working. So my question is : "Is it possible to store JSON file in an ENV variable ?"

miken32
  • 42,008
  • 16
  • 111
  • 154
Quentin P.
  • 373
  • 1
  • 3
  • 7

6 Answers6

19

Convert the JSON object to string and store it in the ENV

You can use JSON.dump to convert JSON object to string

and then in your controller JSON.parse(ENV['CLIENT_SECRET'])

Alternatively

you can create a google_session.rb inside initializers folder

$google_session = GoogleDrive::Session.from_service_account_key(
   # config goes here
)

and in your controller you will have access to $google_session global variable

PGill
  • 3,373
  • 18
  • 21
5

You could just put the item on one line like:

VITE_FIREBASE={"apiKey":"slslsls","slsls":"lelsls"}

You just have to make sure your keys have quotes in them.

and get them (SvelteKit example) like so:

const p = process?.env ? process.env : import.meta.env;

const firebase_config = JSON.parse(p.VITE_FIREBASE);

J

Jonathan
  • 3,893
  • 5
  • 46
  • 77
2

Yes. It is possible to store json file in variable. However there is one small change needed :

\\\"type\\\": \\\"service_account\\\",

Do this for every double quote inside the curly braces of json.

gkr2d2
  • 693
  • 2
  • 9
  • 20
  • Thank you for your answer but the problem remains the same as further explained in my answer below. – Quentin P. May 23 '19 at 15:12
  • It seems that there are spaces between two ```\```. It shouldn't be like that. – gkr2d2 May 23 '19 at 15:14
  • True, I have deleted all the white spaces but the issue still remains. – Quentin P. May 23 '19 at 15:22
  • Okay. Sorry then. – gkr2d2 May 23 '19 at 15:45
  • 8
    In NodeJs for example you can simply include your JSON as an environment variable value like `SURVEY_OBJ={"IncludeSurveys" : ["abc","wxy","z"]}` and then parse that environment by simply using `let myObj = JSON.parse(process.env.SURVEY_OBJ)`. `echo myObj.IncludeSurveys[1]` should print out `wxy`. So no need to escape quotes or remove spaces. – w. Patrick Gale Mar 23 '21 at 19:00
  • 2
    @w.PatrickGale your comment deserves to be the answer, IMHO – Igor Soloydenko Dec 01 '21 at 10:38
  • @w.PatrickGale offers the best solution. The only catch with Rails env variables is that the JSON object must all be on one line, not simply pasted in as multi-line JSON. – Jamie Buchanan Jul 15 '22 at 09:41
1

The solution I came up with was base encoding the json object and store it and then decode it upon a request of using it.

Philip
  • 6,827
  • 13
  • 75
  • 104
  • I personally do this as well, avoids having to escape characters as a env var string. I do minify before converting to base64 just to save some chars though. – James White Jun 17 '22 at 07:04
1

You have to minify your JSON and change all \n to \\n:

CLIENT_SECRET={"type":"service_account","project_id":"gobirdie-landing-page","private_key_id":"xxxxx","private_key":"-----BEGIN PRIVATE KEY-----\\nxxxxx\\n-----END PRIVATE KEY-----\\n","client_email":"xxxxxxx@gobirdie-landing-page.iam.gserviceaccount.com","client_id":"xxxxxxxxx","auth_uri":"xxxxxx","token_uri":"xxxxxxx","xxxxxxxx":"xxxxxxxxx"}
Bart
  • 2,606
  • 21
  • 32
0

If you store the account key as a hash in Rails credentials or DOT ENV, like so

google_drive:
  account_key:
    type: service_account,
    project_id: gobirdie-landing-page,
    client_email: ...,
    client_id: ...,
    private_key: "-----BEGIN PRIVATE KEY-----...\n-----END PRIVATE KEY-----\n",
    auth_uri: https://accounts.google.com/o/oauth2/auth,
    token_uri: https://oauth2.googleapis.com/token,
    auth_provider_x509_cert_url: https://www.googleapis.com/oauth2/v1/certs,
    client_x509_cert_url: ...,
    universe_domain: googleapis.com,

You can do this to generate a session:


session = GoogleDrive::Session.from_service_account_key(
  StringIO.new(JSON.generate(
    # or ENV['google_drive']['account_key']
    Rails.application.credentials.google_drive.account_key
  ))
) 

spreadsheet = session.spreadsheet_by_title("My Spreadsheet")
worksheet = spreadsheet.worksheets.first

Mark Swardstrom
  • 17,217
  • 6
  • 62
  • 70