Have you ever built a project using an API that you wanted to post in a public repository so that you can share your code with the world? Perhaps you hard-coded in your API key and called it good. Well, did you know that there are malicious actors out there who use tools to scan public repositories for API keys? Without the proper security measures, they can have access to your secret key and do a number of things with it, including shutting down your service entirely. But no need to fear, environment variables are here to save the day!
Step 1: Create a .env
File
In your project folder, create a file called .env
at the same level as your /src
directory. Inside this file, you’ll store your API key. The standard naming convention is all caps with words separated by underscores. If you're using React, the name must start with REACT_APP_
. Here’s what a valid .env
file can look like:
API_KEY=your_api_key_here
REACT_APP_API_KEY=your_react_api_key_here
Step 2: Access the Environment Variable
Next, in the file where you want to use the API key, create a variable that references your .env
file like this:
const apiKey = process.env.REACT_APP_API_KEY;
Now you can use the apiKey variable to represent your API key while keeping it hidden.
Step 3: Add .env
to .gitignore
Finally, ensure your .env
file is not uploaded to your repository by adding it to your .gitignore
file:
.gitignore
.env
Pro Tips:
-
Restart Your Development Server: Remember to restart your development server after making changes to your
.env
file. Otherwise, your changes won’t take effect! -
Frontend Security Limitation: While
.env
files are great for hiding keys during development, remember that environment variables used in React are embedded in the build and can be accessed by anyone who inspects the client-side code. For truly sensitive keys, consider using a backend server to handle API requests.
Example Usage:
Here’s how you might use the apiKey
variable in an API call with fetch
:
const fetchData = async () => {
const apiKey = process.env.REACT_APP_API_KEY;
const response = await fetch(`https://api.example.com/data?api_key=${apiKey}`);
const data = await response.json();
console.log(data);
};
Wrap-up
And just like that, your API keys are safe and you may share your code online without worry. Give it a try in your next project and let me know how it goes! Do you have another good way of hiding API keys? Share it down below- I’d love to hear your thoughts!
Top comments (9)
Folks should stop using environment variables for secrets, this is bad advice. Each and every process has environment variables loaded into process memory at predictable locations, making it easy for attackers to find with a number of different vulnerability classes.
If you put your password/token/key into environment variables, they are not "safe," they're just slightly safer than when you put them in version control.
A better approach is to use a tool like AWS SecretsManager, 1Password APIs, or even BitWarden to store them encrypted, and only fetch them when you need them. After using them.
Compromised secrets remain a leading cause of breaches, including Ransomware. We should all do more to protect our secrets.
A perfect follow-up article would be: Stop using archaic .env files: Why you need hierarchical configuration systems right now.
Both approaches have their use cases IMHO. The biggest advantage I can see in hierarchical config is the ability to fetch from secret vaults in real time rather than having to store multiple tokens and what not in the MacBook of each developer, which on it's own can be an attack vector.
It's just a plain text file, just like a .json file. The problem is perpetuating the concept of "an environment" in the browser. This artificial construct is unneeded. The whole
dotenv
is unneeded, even in NodeJS where there is an environment. Hierarchical configurations are much more versatile in every way. It is just dumb to keep .env files around.Aren't the hierarchical config files not "around" somewhere as well? Hocon, json... Who cares. Even if you store these in the DB (which is probably the most common way to implement a hierarchical configuration system) you'll have the migration or script to spin up a new environment based off of that given config, and none should be present in your repo or exposed to the public.
For a project (no matter how big) that doesn't need many configurations a dotenv is just fine, same goes for small projects which entire config is a handful of tokens and a flag.
Each and every tool has its pros and cons, glorifying a tool or applying the golden hammer approach only leads to dramas 😂
It is "finer" to not use .env at all.
That's it. Why .env that forces you to install a BIG package like
dotenv
? How is that better?.env files are natively supported since long ago... Also
isn't bad, either.
PS: env files are read on startup so make sure you restart the server when making changes there.
That wasn't long ago, and that's only in NodeJS. In browser projects are still a hack.
All key are sensitive keys in a production environment.