Edit
Page
Securely Using Environment Variables in NodeJS cover image

Securely Using Environment Variables in NodeJS

Using `dotenv`

updated over 5 years ago

nodejs (3)
secrets (2)
tokens (2)
dotenv (1)

Handling Secrets & API Tokens Safely

credit: john-salvino-417565-unsplash.jpg

Related Article: Protect Your Tokens

Let’s quickly recap the difference between secret and non-secret.

  • 🔒 Secret keys MUST use a custom server (e.g. Node/Express/Heroku) in order to hide (proxy) requests to 3rd party API services.
  • 🌍 Non-secret keys describes keys which can be sent to the browser.


We’ll focus on dealing with 🔒 Secret keys using Environment Variables in this article.

Code examples are included below.

Overview

To safely access secrets in your NodeJS code:

  1. Replace hard-coded keys with environment variables. e.g. process.env.API_SECRET
  2. Use a library like dotenv along with a .env file. Add your previously hard-coded secrets to the .env file.
  3. Verify .env line in your .gitignore file!

DON’T create a .env file on deployed servers. Use your hosting services’ (e.g. Heroku, Netlify, AWS EC2) provided environment variable management tool: e.g. dashboard or command line.

️ Code Example:

We’re going to define a few files.

  1. .env
  2. ./db/connection.js
  3. ./api/users.js

First, install the dotenv package.

npm install dotenv

Next, create a .env in the root of your project.

# .env
PGDATABASE="postgres"
PGHOST="localhost"
PGPORT=5234
PGUSER="postgres"
PGPASSWORD="password"

NEVER commit .env file.

❌ Avoid creating .env on servers.

Check your Hosting Provider docs to set up environment variables.

To easily make sure your .gitignore has a .env line in it.

# Automatically update .gitignore
# Run in terminal:
[ "$(grep '^.env' .gitignore)" == "" ] && echo '.env' >> .gitignore
# note: no output will print

The ./db/connection.js provides a shared pg.Pool instance. It’ll be used to query the database.

// ./db/connection.js
require('dotenv').config(); // ✅ Load .env file
const pg = require('pg');
const {PGUSER, PGHOST, PGPORT} = process.env;

if (process.env.NODE_ENV === 'development')
  console.log(`Connecting to ${PGUSER} @ ${PGHOST}:${PGHOST}`)
;
// ^^ only for showing debug connection vars

// pg automatically uses PG* env variables
module.exports = new pg.Pool();

The ./api folder contains interfaces to your tables/views.

Here’s an example ./api/users.js for the users table.

// ./api/users.js
const db = require('../db/connection.js');

module.exports = {
  findUsername: function(username) {
    return db.query('SELECT * FROM users WHERE username=$1', username);
  }
};

Never commit your .env secrets to git!

Don’t share .env files on a team. *

* Every new development laptop or desktop should generate new access keys & tokens. If it’s not possible, use plenty of care sharing your .env (in cases where a service might invalidate all older keys, or you have a paid API’s limited access token.)

⚠️ Important: if necessary, always use a secure messaging service (preferably with expiring message support.)

Good luck and let me know if you have any questions! 🎉