I am finishing up a node express App where I have an API key for Sendgrid and Stripe but I am not sure how to store these in my app that will be deployed on Heroku (also a few other variable I would like to store similarly like db password and what not). I saw online many people were using process.env so after some looking I tried using dotenv npm and even with some problems with the structure of the app after trying to use the dotenv for my sendgrid key I got an error every time.
My question is can somebody supply some detailed instructions or a way to securely store API keys in my node express app that I will be deploying to Heroku?
P.S. I followed a tutorial to implement Passport.js for Oauth2 through facebook, google and linkedIn so users can easily log in to the application. The app secrets, id and callbacks are retrieved from a json file in a folder call config in my application. Is this information secure at least in its placement and retrieval in the application? Should I do something similar for my sendgrip and stripe api keys? (picture below)
You can set up your folder directory like this:
config.js
var config = {};
//development
var env = process.env.NODE_ENV || 'development';
if(env === 'development'){
config = require('./env/development');
}else if (env === 'test'){
config = require('./env/test');
} else if(env === 'production'){
config = require('./env/production');
}
module.exports = config;
development.js
var envFile = __dirname + '/env.json';
var jsonfile = require('jsonfile');
var envVars = jsonfile.readFileSync(envFile);
module.exports = {
value: envVars["VALUE"]
};
production.js
module.exports = {
value: process.env.VALUE
};
test.js
module.exports = {
value: 'Some value'
};
The basic idea here is that each developer can configure their own keys in their own env.json file. For production, you can store these in a secure file somewhere and load them into the environment however you want prior to running your application. Using heroku, it makes it easy to configure these environment variables and stores them for you. Check it out here
You can also ommit any details you may not need like development or test stuff.
Edit: An example
Try this from the command line first to get an idea of what is happening. In this example I am using linux. If you are using anything else just research how to set the environment variables in the command line you are using.
app.js
var config = require('./config/config');
//get value from config
var value = config.value;
Set environment variables from bash command line
$: VALUE="my value"
$: NODE_ENV="production"
$: export VALUE
$: export NODE_ENV
Run the application
$: node app.js
or if you are using npm scripts
$: npm start
When you run the application node will automatically load process.env with every environment varaible defined within the command line shell. Now, if you are using heroku you can follow the link I posted earlier in this answer and you don't have to set them. Just define them in heroku interface and it will load them for you.
Related
I have deployed a simple app to Heroku with a JavaScript file serving an HTML page via Express. The code is pulled from a private Git repo.
Now, I have a password stored in this JavaScript file and my question is: can an user find that password? It's only used in requests made from Node to external resources.
This is part of the server-side JavaScript code where I serve the page:
const app = express();
const express = require('express');
const password = ******:
app.use(express.static(__dirname + '/dist/shop-info-angular'));
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname + '/dist/shop-info-angular/index.html'));
});
In this example your JavaScript file will run on the server and just send the response to the user. As long as the index.html that you're sending in your response doesn't also contain the password you should be fine.
However, Heroku offers a better way to configure applications that is especially well-suited to sensitive information like passwords. Update your code to get the password from the environment:
const password = process.env.PASSWORD;
and set an environment variable on Heroku:
heroku config:set PASSWORD=mysecretpassword
You can also use environment variables locally, but note that they'll be different from the ones you set on Heroku. After all, they're environment-specific. Something like dotenv can help.
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!
I've got a large Node.js Express API to build, so I want to make sure my solution architecture is stable and scalable.
The routes are defined each in its own separate file and stored in /routes folder. There's an index.js file as well, where all of the child routes are registered to the master router.
There's an application configuration file /config/app.js:
module.exports = {
development: {
configVar: 123
},
test: {
configVar: 456
},
production: {
configVar: 789
},
}
The config object is loaded in the main application index.js file:
const path = require("path");
const env = process.env.NODE_ENV || "development";
const config = require(path.join(__dirname, 'config', 'app.js'))[env];
Now that I have the config object, I'd like to pass it down to whatever consumer. For Express app it's mostly the routes. Loading the config repeatedly in each module would be kind of redundant. So I have set up my main routes module (/routes/index.js) as follows:
const express = require('express');
const router = express.Router();
module.exports = {
init: function(config) {
router.use('/test', require('./test').init(config));
return router;
}
}
And the /test route (/routes/test.js):
const express = require('express');
const router = express.Router();
module.exports = {
init: function(config) {
router.post("/", function(req, res) {
res.send('hello world');
});
return router;
}
}
I also like that with this structure I can mock the config object when testing the routes. My question is, if this can be considered a good pattern for Express application, or perhaps there is some convention to follow.
There are many ways to skin a cat and many more ways to setup an express project.
The one thing that jumps out at me as a good thing to change is your configuration method. Your approach makes total sense, but there's a module called config which works in much the same way you've illustrated but you won't need to list every option for every environment.
Using this module you can have a default.json file which contains all of your base configurations. You can then override it with a file which matches the name of your environment such as development or test without having to do it by hand.
More importantly, it will also let you map from your applications configurations to Environment Variables. You very rarely want to store your applications configuration values in the codebase itself, especially when we're talking API keys and secrets. The last thing you want to do is commit API keys / secrets into version control. The config module linked above will allow you to define environment variable mappings which means you can feed them in via the systems environment variables instead.
I should note finally that there are many modules which act in a similar way to config and they all function slightly differently. You might also want to consider nconf which is also a brilliant module.
It is not uncommon to want to be able to have non-relative imports, for example, for configuration, etc...
In the world of running a node executable on your own (development env, any cloud provider... things like that) you can simply set an env var and have it respected by the node runtime.
Imagine a project structure like so:
dist
|--foo
|--bar
|--baz
app.js
|--config
in app.js with NODE_PATH=dist, I can simply require('config') and have what I need.
Within Azure App Services, it appears to ignore NODE_PATH from Application Settings. Is something missing or is this not possible?
In Azure App Services, you can set the NODE_PATH environment variable in the Azure portal with the following steps.
1, Create the D:\home\site\my_node_modules\config directory and put the index.js file in where. In this case, I just export the "name" variable.
// D:\home\site\my_node_modules\config\index.js
var name = "foobar";
// export it
exports.name = name;
2, Navigate to your App Service in the Azure portal, click on Application settings in the SETTING menu and then set the NODE_PATH variable as below:
3, In the app.js file, you can simply require('config') like this:
var http = require('http')
var config = require('config')
http.createServer(function (req, res) {
res.end(config.name)
}).listen(process.env.PORT || 3000)
4, At last, it works fine.
Question concerns setting up the development environment (later on other environment like production)....
Using latest of Node, Passport, and Grunt but Express still in the 3 chain.
Working on an application leveraging external authentication only (i.e. no local Passport strategy). The oauth client id, secret key and callback configuration per strategy (i.e. Google, Facebook etc.) is nothing (obviously) to be housed in Git.
Wondering how people tackle this with different environments? Just getting my feet wet with Grunt so I am currently registering a task (after the initConfig which reads my package.json) that reads a authentication configuration (excepting an authentication property in package.json):
grunt.registerTask('auth', function() {
var pkg = grunt.config('pkg');
var util = require('util');
if (grunt.file.exists(pkg.authentication)) {
grunt.log.writeln(util.format('Setting up authentication with %s', pkg.authentication));
var auth = grunt.file.readJSON(pkg.authentication);
.... // move auth data into a auth.js read by the application
} else
grunt.fail.warn(util.format('%s not found (authentication property in package.json), neccessary for authentication but not managaged by Git', pkg.authentication));
});
Basically, the developer/installer is responsible for having a private (not managed by Git), local settings for authentication. Something like:
{
'googleAuth' : {
'clientID' : 'your-secret-clientID-here',
'clientSecret' : 'your-client-secret-here',
'callbackURL' : 'http://localhost:8080/auth/google/callback'
}
}
A simple copy of the JSON contents into a auth.js file put in the build directory required by the application will work.
Better way?