Node.js: Handle secrets

How to handle secrets with Node.js

👋 Welcome to the Stackhero documentation!

Stackhero offers a ready-to-use Node.js cloud solution that provides a host of benefits, including:

  • Deploy your application in seconds with a simple git push.
  • Use your own domain name and benefit from the automatic configuration of HTTPS certificates for enhanced security.
  • Enjoy peace of mind with automatic backups, one-click updates, and straightforward, transparent, and predictable pricing.
  • Get optimal performance and robust security thanks to a private and dedicated VM.

Save time and simplify your life: it only takes 5 minutes to try Stackhero's Node.js cloud hosting solution!

When your Node.js project interacts with a database, object storage, or an external API, it is important to store credentials, such as usernames, passwords, or tokens, securely. These credentials are often referred to as "secrets". Keeping your secrets confidential is essential for maintaining the security of your application.

At first, you might consider writing your credentials directly in your code, like this:

// Connecting to a PostgreSQL database
const pg = new Client({
  host: '<XXXXXX>.stackhero-network.com',
  user: 'admin',
  password: 'myPassword',
  database: 'admin'
});

However, this approach is not secure. This is because your secrets could easily end up in your Git repository, making them visible to anyone with access. Even if you think only you have access, it is a bit like leaving a Post-it note with your passwords on your monitor and hoping nobody else notices. This can eventually lead to serious security issues.

In addition, hard-coding secrets makes it difficult to manage different environments, such as development and production, smoothly.

A common best practice in the industry is to store secrets in environment variables.

Environment variables are defined outside your code and are set before Node.js starts. The idea is to define all your secrets using environment variables, so they are never hard-coded in your application.

You can define an environment variable by setting it at the start of your Node.js command, like this:

MY_PASSWORD=myDevelopmentPassword node app.js

This command creates a variable named MY_PASSWORD with the value myDevelopmentPassword. The format is straightforward: <KEY>=<value>.

By convention, environment variables are written in capital letters. It is worth noting that environment variables can only hold strings, not arrays or objects.

Inside your app.js file, you can access your environment variable using process.env, like so:

console.log(process.env.MY_PASSWORD);

This will display myDevelopmentPassword.

Now, your password is defined outside of your code. This helps ensure it will not accidentally end up in your Git repository.

If you are using Stackhero in a production environment, you can define a new environment variable named MY_PASSWORD with the value myProductionPassword right from your Node.js service dashboard. This makes it easy to keep things running smoothly between environments.

Example of Node.js configuration on the Stackhero dashboardExample of Node.js configuration on the Stackhero dashboard

With this setup, your password is no longer stored in your code, and you can easily use different credentials for development and production environments.

In real-world projects, you often need to manage multiple secrets. For example, connecting to a database may require a hostname, username, and password.

Handling a single secret is simple, but juggling several can quickly become awkward. Imagine starting your application with a command like this:

POSTGRESQL_HOST=<XXXXXX>.stackhero-network.com POSTGRESQL_USER=admin POSTGRESQL_PASSWORD=myPassword node app.js

This quickly becomes hard to read and maintain. In production, you might need even more variables, making this approach impractical.

That is where the dotenv library can help.

With dotenv, you can store secrets in a separate file called .env.

To get started, you can install the dotenv library by running:

npm install dotenv

Next, create a .env file to hold your variables:

POSTGRESQL_HOST=<XXXXXX>.stackhero-network.com
POSTGRESQL_USER=admin
POSTGRESQL_PASSWORD=myPassword

To keep your secrets safe, make sure your .env file is not added to your Git repository. You can do this by adding it to your .gitignore file:

echo ".env" >> .gitignore

Finally, load the dotenv library at the top of your app.js file:

require("dotenv").config();

With this setup, when you start your application using node app.js, dotenv reads your .env file automatically on your development machine. In production, you do not need the .env file. Environment variables are pulled directly from your Node.js service configuration, which you can manage through the Stackhero dashboard.

Now that we have covered the theory, let us look at a real example.

You can find a complete, working sample here: https://github.com/stackhero-io/dotenvWithNodejs

With these techniques, you can manage your secrets in a flexible and secure way, making the process straightforward and efficient.