Questionings about keys and OAuth - node.js

I am building a node.js app (script?) that is using google-auth-library and there is something that I don't understand.
I have generated the JSON file containing my OAuth2 client id keys using Google Developers Console, and I am using it in my script the following way :
const keys = require('../client_secret.json');
const oAuth2Client = new OAuth2Client(
keys.web.client_id,
keys.web.client_secret,
keys.web.redirect_uris[0]
);
// Generate the url that will be used for the consent dialog.
const authorizeUrl = oAuth2Client.generateAuthUrl({
access_type: 'offline',
scope: [
'https://mail.google.com',
'https://www.googleapis.com/auth/drive'
]
});
Then, I am opening the consent dialog, and getting my token back, etc. My app has the will to be open source, so my question is: should I let my client_secret.json file in my repository so other users can use it using their Google account?

The client token must be kept secret: extract from Google documentation
After creating your credentials, download the client_secret.json file from the API Console. Securely store the file in a location that only your application can access.
Your application will remain open source as authentication is a service not source code.
To manage your secret, I would suggest you to use environment variables accessible via process.env.YOUR_VARIABLE.
It does exit packages that will make it easy to handle between you different environments, my favorite is dotenv. dotenv loads environment variables from a non required .env file. You would typically use it in your development environment, you must not commit it!
Dotenv do not require the presence of the .env file, and won't override an environment variable that is already set anyway. You will have to define the environment variables in production and test environment the way your prefer.
You can also see this article

Related

Node.js google cloud storage authentication using credentials token

I'm trying to authenticate with google cloud storage using a credentials token.
Can't find an example anywhere in the node.js GCS api docs on how to do so.
They instruct to generate and download a json file that contains your private key and then link to its path on your file system like so:
const storage = new Storage({keyFilename: "key.json"});
And this works just fine.
However I don't want to save my key as a JSON file, but create the credentials and save them as environment variables something like so:
const gc = new Storage({
credentials: {
client_email: process.env.CLIENT_EMAIL,
private_key: process.env.SECRET_KEY
}
});
I tried getting this token from the settings of the bucket, from the interoperability menu, using service account HMAC access keys.
When I try to upload/delete files from the bucket with the authentication method above I get the following error:
Error: error:0909006C:PEM routines:get_name:no start line
Appreciate any help on the matter
The error
Error: error:0909006C:PEM routines:get_name:no start line
was actually caused because of a dotenv ohmyzsh plugin I downloaded a while back and just forgot about. Was very hard to debug. Turns out the google secret key has \n in it and the ohmyzsh dotenv plugin failed to parse them correctly. So deleting it worked for me.
If you use the JSON api (you most likely are) These are the credentials you need to authenticate, so you can just take the relevant info and put it in a .env file in your project, if you don't like putting the path to the json file:
const gc = new Storage({
projectId: process.env.GOOGLE_STORAGE_PROJECT_ID,
scopes: 'https://www.googleapis.com/auth/cloud-platform',
credentials: {
client_email: process.env.GOOGLE_STORAGE_EMAIL,
private_key: process.env.GOOGLE_STORAGE_PRIVATE_KEY
}
})
Still am not 100% sure on how to authenticate using a token + secret.
I am getting close to the answer and will update this post in the future if I find it. Posting a helpful link: google-auth-library-nodejs hoping someone beats me to it :)
Error: error:0909006C:PEM routines:get_name:no start line can be solved by converting '\n' to the actual char \n using something like:
process.env.ATHENA_PRIVATE_KEY.replace(/\\n/g, '\n')

Firebase Auth Are my variables secure/safe?

I am currently using heroku to store my environmental variables for my firebase authentication initialisation. I am using my server to get the environmental variables and send it to the client using socket.io. Below is what I mean.
1) Example of sending environmental variable to client from server:
socket.emit('value', process.env.apiKey);
2) storing it as data[0] in the client:
socket.on('value', function(data) {
firebase.initializeApp({
apiKey: data[0],
});
})
Is this safe? Can someone from the client retrieve the value of the apiKey if I save it like this on the client?
Thanks
If the data is used from the client, it can be gotten from there by a malicious user. Looking up the data dynamically like you do here, merely adds an extra step.
But the data that you pass to initializeApp is basic configuration data that allows the code to find your Firebase project on the servers. It is not a secret, it's not a security mechanism ,and it can be safely shared with your users. See my answer here, for why you don't have to try and secure this data: Is it safe to expose Firebase apiKey to the public?

How to use environment variables secrets safely in production

I would like to use environment variables to securely hold secrets with pm2.
I have a reverse proxy to an express backed server that uses a database with a password each time it connects to preform a query.
I would like to access it normally from the program:
procsess.env.my_secret
but I'm assuming that simply setting the variable at run time like the following isn't safe:
MY_SECRET="secret password" pm2/node my_api_server.js
How should I set the secret password considering I'm using pm2 and I would like the variable to persist through restarts/crashes?
I should note that different environment handling and passing code to other developers through the VCN is less important to me.
Storing API keys or credentials using .env gets exposed to the client on Production!
By React docs -
WARNING: Do not store any secrets (such as private API keys) in your React app!
Environment variables are embedded into the build, meaning anyone can view them by inspecting your app's files.
It's advised to store all env keys directly on the server and the server should be used as a mid point between the client and the API. This way the key is applied directly on the server and is not exposed in the front end. You can check out respective documentation on how to set up env variables on your particular server.
Front End Code
fetchData = () => {
fetch('/users', { method: 'POST', body: JSON.stringify(data) }
.then(res => res.json())
}
Server Code
app.post('/users', (req, res) => {
const API_KEY = process.env.API_KEY;
connection.query(`/apiPath/${API_KEY}`)
}
In past ReactJS projects with Express backends that need to connect to a database, I've used the dotenv package on NPM. Once added as a dependency to your project, you will create a hidden .env file in the root of your server filestructure.
In that .env file, you can create environment variables. These variables will need to be prefixed with REACT_APP like the following:
REACT_APP_DBURI=<conn string here>
REACT_APP_MAILGUN_API_KEY=<key string here>
REACT_APP_CAPTCHA_SECRET_KEY=<key string here>
You need to require the package as follows in your code:
require('dotenv').config();
You can reference them in your server.js (or whatever) code as:
process.env.REACT_APP_VARIABLE_NAME
This Medium article has a full explanation.
Hope this helps!

Storing the googleapi Secret Keys in Firebase Environmental Variables

Question
I would like to store a Secret API Key for googleapis in a secure location. When I store the Secret API Key from googleapis as a Firebase Environmental Variable, the private_key is not processed the same as when I require("./privatekey.json"); See Issue below:
Context
I have downloaded and decoded a Secret API Key from Google. Most examples show saving the decoded JSON file within your project path and using require to pull the token into to code.
const SERVICE_ACCOUNT_KEY_FILE = require("./privatekey.json"); <----- This is Bad!!
const SERVICE_ACCOUNT_EMAIL = 'email#serviceaccount.com';
const jwt = new googleapis.auth.JWT(
SERVICE_ACCOUNT_EMAIL,
SERVICE_ACCOUNT_KEY_FILE.private_key,
null,
['https://www.googleapis.com/auth/analytics.readonly']);
I have used the firebase-cli to firebase functions:config:set Firebase Environmental Variables. When complete and redeployed, I run firebase functions:config:get and I see:
"googleapi_credentials": {
"private_key": "-----BEGIN PRIVATE KEY-----\\nMIIE ... q0DEg==\\n-----END PRIVATE KEY-----\\n",
Issue
When I configure googleapis.auth.JWT() I need to provide the googleapis Secret API Key. When I use require to pull in the Secret API Key, the requests work.
However, if I try to access the Firebase Environmental Variable to provide the Secret API Key, the requests fail.
var jwt = new googleapis.auth.JWT(
functions.config().googleapi_credentials.client_email,
functions.config().googleapi_credentials.private_key, <----- NOPE!
null,
['https://www.googleapis.com/auth/analytics.readonly']);
Debug
To see what's different I compared the console.log() of the two tokens in the firebase functions log view. The token I stored in the JSON file and in Firebase Environmental Variables looks the same in code, that is, both strings match and they include many \n (line breaks).
Now, when I review what the console.log() returns in the Firebase Functions Logs, I see different tokens.
console.log("JSON Private.Key", privatekey.private_key)
The view in the logs returns a formatted string with all \n replaced by line breaks, and the token is accepted.
console.log("Private.Key", functions.config().googleapi_credentials.private_key)
Logs returns a sting will all \n replaced by \\n., and the token is not accepted.
Final Note
The googleapis.auth.JWT() function can take an object for it arguments? Do I need to take this into consideration if using Firebase Environmental Variables?
Firebase environment details have a problem with add slashes and can break \n strings.
There is an open ticket on GitHub which should be referred to; github.com/firebase/firebase-tools/issues/371
Here is a hack I found posted by YunjorGlez. This worked for me.
You can use .replace(/\n/g, '\n') to remove the extra \ that is being added to the private_key.
const serviceAccount = functions.config().fireenv;
admin.initializeApp({
credential: admin.credential.cert({
"projectId": serviceAccount.project_id,
"private_key": serviceAccount.private_key.replace(/\\n/g, '\n'),
"clientEmail": serviceAccount.client_email
}),
databaseURL: whatever,
...
});

How can I access an environment var in other modules

I use the jsonwebtoken module to Encode and Decode JWTs.
The Secret-passphrase is being saved in a config.yml file, which is being loaded in my main index.js Javascript and stored into an app Environment var app.set('jwtToken', config.jwt.token).
How can I access this environment var in another module (for example the Auth-Route Module).
Can I pass it somehow to this file?
Many thanks
I think you will need access to your app instance to access the jwtToken var in app. Alternative for you would be to pass your jwtToken as an process environment variable via
JWT_TOKEN=xyz node server.js
Now you could access it via process.env.JWT_TOKEN

Resources