Node.js

How to manage secrets for Node.js applications

This guide will walk you through the steps necessary to inject secrets as environment variables into Node.js applications.

The concept will be demonstrated on an app that uses dotenv, however the same principles will also work for frameworks like Express.js.

Handling secrets with dotenv

In Node.js secrets are usually loaded from env files using the dotenv module. This is done in order to separate the secrets from source code. For example an env file might look like this:

DB_HOST=localhost
DB_USER=root
DB_PASS=s1mpl3

Then, in the app code you would inject the secrets like so:

require('dotenv').config()

const db = require('db')
db.connect({
  host: process.env.DB_HOST,
  username: process.env.DB_USER,
  password: process.env.DB_PASS
})

Usually you would also put an example.env file in your repository, to share the structure of the file with other developers.

DB_HOST=<HOSTNAME HERE>
DB_USER=<USERNAME HERE>
DB_PASS=<PASSWORD HERE>

In a large-scale application different .env files are needed for each environment.

So, in such a project you would have the following setup for handling secrets:

Node.js with dotenv diagram
Project structure with dotenv

While this removes hardcoded secrets from source code, it doesn’t solve your problem completely; Now you need to find a way to provision your app with the .env file.

This guide will show how you can remove the secrets from the .env file altogether, so that it can be safely checked into source control and shipped with your application.


Before you begin

Before you start using SecretHub with Node.js, make sure you have completed the following steps:

  1. Install the SecretHub CLI for your OS.
  2. Sign up for a SecretHub account.

This guide uses Node.js version 8.10.0

1. Write your secrets using SecretHub

In order to inject the secrets you first need to store them in a repository.

To create a repository, run:

secrethub repo init your-username/example

To store the username in the repo, run the following command and then enter the username:

secrethub write your-username/example/username

And similarly for the password:

secrethub write your-username/example/password

2. Rewrite the .env file

Next, you can rewrite your env file and reference the secrets in it. If you rename it to secrethub.env it will automatically be detected in the last step.

DB_HOST = localhost
DB_USER = {{your-username/example/username}}
DB_PASS = {{your-username/example/password}}

Given that it no longer contains secrets, it can be safely checked into source control.

If you want to use different secrets for each environment (e.g. env=dev or env=prd) check out the environment file syntax.

3. Remove the dotenv dependeny

You can now safely delete the example.env and remove the dotenv dependency from your project. Your code should now look like this:

const db = require('db')
db.connect({
  host: process.env.DB_HOST,
  username: process.env.DB_USER,
  password: process.env.DB_PASS
})

4. Pass the secrets to the app

Finally, to start your app and have the secrets it needs automatically provisioned all you need to do is wrap it with the run command and execute it:

secrethub run -- node app.js

This command will set the environment variables as specified in the secrethub.env file and run your app.

With SecretHub your project structure will look like this:

Nodejs with SecretHub diagram
Project structure with SecretHub

You have now successfully removed the secrets from the .env file and automatically provisioned them at runtime!

Finally, you can clean up the example repository used in this guide by running:

secrethub repo rm your-username/example

See also

  1. If you want to deploy your project on AWS check out our AWS integration guide.
  2. To learn more about the run command take a look at the documentation.
  3. If you want different secrets for each environment or user check out the environment file syntax.

Happy coding!