node.jsexpressjwtenvironment-variables

Why and how to put secrets in environment variables in Node.js?


I'm relatively new to Node.js and Express and I was following a guide on adding authentication using JWT to my site found here: Medium. I'm confused by one point of this guide, about using secrets, that says:

This secret will be read by JWT library while creating and validating tokens. In production, we need to store this secret in environment variable instead of a file.

In the guide, they placed the secret inside a config file. I wish the guide described why exactly the JWT secret should be an environment variable instead of in a config file, but it's pretty vague. So why should secrets be environment variables, and what are other best practices for using secrets? I've decided to use Passport & Express Sessions for authentication instead of JWT, but I'd think it still applies to session secrets.

My next question is how would I exactly set a secret in an environment variable? I'm not using the guide anymore, but how would somebody that is using it convert that config file into an environment variable? And lastly, what do you usually use environment variables for in a typical Node.js app?


Solution

  • Why should a secret be an environment variable, instead of being stored in a config file?

    While working on projects, you will end up uploading your code on github, which is accessible to everyone. If you store your secrets in a config file, anybody with a github account will be able to read it, and hence it is a security risk. Storing the secrets as environment variables ensure their safe-keeping. Your config file should read these values from the process.env object. Something like this:

    const jwtSecretKey = process.env.JWT_SECRET_KEY;
    const googleApiKey = process.env.GOOGLE_API_KEY;
    const serverPort = process.env.PORT || 8000; // 8000 is the default value in case if the env variable has not been set
    
    module.exports = {
       jwtSecretKey: jwtSectetKey,
       googleApiKey: googleApiKey,
       serverPort: serverPort
    }
    

    And any other piece of code using these secrets should require the config file.

    const config = require('./config');
    ...
    
    jwt.verify(token, config.jwtSecretKey);
    

    Along with storing secrets as environment variables, you should also store any environment specific values as environment variables. For example, say your NodeJS server (thats is connected to a hosted Database) is run on three environments - Development, QA and PROD. Each of these environments will have different information regarding the DB HOST and PORT, the environment should connect to. Environment Variables are a good way to store the DB Host and Port on each individual environment, and to use the same code across all environments to connect to different databases by reading the environment variable.

    How to store the values as environment variables - One way of doing it is manually, though I wouldn't recommend it. One way is use of shell scripts. It actually depends upon your infrastructure.

    You should also add your *.env to the .gitignore file So pushing it to the public will ignore the file and you have only one file with all the environment variables.