How do I hide an API key in Create React App?
Asked Answered
B

13

165

I made a weather app in Create React App (create-react-app). How do I hide the API key so that I can commit to GitHub?

Right now, the key is in App.js:

const API_KEY = "123456";
Backsight answered 9/2, 2018 at 6:17 Comment(8)
use ENV vars. Or keep it in secret.yml file. And then put the file in .gitignore. And then using JS read yml, load it to ENV.Endocarp
see github.com/motdotla/dotenvEndocarp
Possible duplicate of Using API keys in a react appPreindicate
You can't hide secrets in a react app. See https://mcmap.net/q/101225/-using-api-keys-in-a-react-appPreindicate
@E. Choi Please fix the selected answer... the wrong is is selected.Lesotho
This thread is very popular but it lacks one (rare) use case: how to store client secret, on client side. In my use case, I don't have any backend (Stripe is the backend), and my app ask for the users limited API key to make requests to Stripe. How to be sure that this key, stored on client side, can't be accessed by other origins ?Deas
The correct answer was in @theprogrammer's commentGroom
All the steps are given here https://mcmap.net/q/99109/-adding-an-env-file-to-a-react-project-duplicateRebellion
F
353

Unfortunately, keeping any key in your React client, even if you are using gitignore and an .env file, is not secure. As pointed out by Claudiu Creanga, React environment variables are embedded in the build and are publicly accessible.

You should really only save API keys or secrets in your backend such as Node.js or Express.js. You can have your client send a request to your backend API, which can then make the actual API call with the API key and send the data back to your client.

Fluorescein answered 18/7, 2019 at 23:8 Comment(15)
This is the correct answer. A client application running on a browser cannot securely store secrets.Moussaka
This should be the accepted answer. I wonder how many people are deploying insecure apps, due to not read this and rely on others anwers.Roue
But the whole point of the API key is to restrict the client not to access backend API without secret API key whereas you guys are saying to let backend handle it. I am sorry I am a little bit confused. could you please add more details on thisMitchell
I was scrolling here finding for the secure solution until I found this which actually answers OP's question correctly. Everything else is either use insecure environment variables or advice on not using environment variables.Amesace
@Mitchell ideally in a React frontend app, the users are the ones who provide credentials (username/password) to access the backend (Node/Express with an authentication service) for which the backend sends a generated token back for the frontend to store in memory (not embedded in HTML/JS, etc.). So now, the frontend can tell the backend to make accesses to third-party APIs, etc. This way we ease the attack surface exposed by the frontend and hide the third-party API tokens in the backend.Amesace
Are all API keys necessarily secret? Google Maps API, for example, seems to encourage the use of its API keys in the front-end. The key is secured in a different way, by allowing the developer to restrict the domains that are allowed to use the key and limiting the Maps services that can be accessed. So, the key itself is not secret, but knowing the secret does you no good unless you own the domain that's allowed to use the key.Bevy
@Bevy That is true, if the API key is designed to be public / used on the frontend, like your example with Google Maps Javascript API, then it is fine to use it there.Fluorescein
This is better than the other answers, but even if it's being requested at runtime they can still look at the network traffic and see what the api key was, right? I mean, you could try to obfuscate it somehow, but it will still be the same problem. As far as I know there is NO way to keep an api key truly secret on a frontend app. Am I wrong?Tawny
I was thinking of the same way you mentioned here but I have a concern, - we need to send a request from the client to get the data. - Anyone can send the same request and get that data, right? - So can you please tell me, How to secure/authenticate the request sent from the client-side?Visser
Firebase in React demonstrates, that some API keys can be exposed. For example Firebase API keys can be exposed and it is answered also in different question.Cordey
@RVRJ, I was wondering about the same things at first, but these questions come from not properly understending Antonia's answer. The react app doesn't fetch the api key from the backend. It sends the request via the backend, which works as a proxy. Only the backend knows the secret key and only the backend actually communicates with the third-party API and therefore the secret key is safely protected from the frontend.Buckden
@lorweth333, But only authenticated users should allow to access the backend. otherwise all can hit the API ?Sallie
@ Shaiju T that is not the concern over here.Groos
There are valid cases where having a key on the client may be acceptable, but you still don't want it in your public source code. My use case is developing a demo electron app using an api that anyone can get a free key for. I want to commit the code to a public github repository for others to use, but they should get their own api keys. If the API key is present in the source code then nobody will bother getting their own and it will probably go over the free key usage limits.Wisnicki
Another alternative is using Next.js to Store Environment Variables. You can access private environment variables in a function. This function runs during build time on the server. So the environment variables you access inside this function will only be available in the Node.js environment.Rondel
R
130

Disclaimer

WARNING: Do not store any secrets (such as private API keys) in your React app!

Environment variables are embedded into the build, meaning anyone can view them by inspecting your app's files.

The following answer provides a correct way to store non-secret data in environment variables. Remember that secret data is accessible through developer tools, making it unsafe to store as environment variables. If you want to store some secret data then storing in the backend is the better option and if the client wants to access secret data, it can be accessed by making a request to the server. (Refer to Antonia's answer for more details on storing secret data.)

As it turns out, create-react-app has some built-in functionality to help you with that. Thank you George Karametas for this insight. To access that functionality, you need to:

1. Create a file called .env in the root of your project's directory.

- your_project_folder
  - node_modules
  - public
  - src
  - .env         <-- create it here
  - .gitignore
  - package-lock.json
  - package.json

2. Inside the .env file, prepend REACT_APP_ to your API key name of choice and assign it.

The create-react-app tool uses REACT_APP_ to identify these variables. If you don't start your API key name with it, create-react-app won't see it.

// .env

REACT_APP_API_KEY=your_api_key  <-- yes
API_KEY=your_api_key            <-- no

// Example (from 이준형's response):
REACT_APP_WEATHER_API_KEY=123456

3. Add the .env file to your .gitignore file.

After you add the line below, save the .gitignore file and do a git status to make sure your .env file does not appear as a new file in git.

// .gitignore

# api keys
.env       <-- add this line

# dependencies
/node_modules
...

4. Access the API key via the process.env object.

To check that you can access your API key, go to your App.js file and add a console.log at the top below the require statements. After saving the file and reloading the page, if the console log does not show your API key, try restarting the react server. Be sure to remove the console log line before committing your code.

// src/App.js

import React, { Component } from 'react';
import './App.css';

console.log(process.env.REACT_APP_WEATHER_API_KEY)

class App extends Component {
...
Ricarda answered 21/5, 2018 at 23:59 Comment(9)
Im getting an undefined. Do we have to import through the App.js file or do we have to export the .env?Goodwill
@Goodwill Make sure you wrap your apiKey in a template literal, because it must be a string. Here is an example of how I have mine setup: pastebin.com/WQ0CzqQy Then make sure you restart your server.Geaghan
Maybe im misunderstanding still... can you take a look at this codepen when you get a chance, not the output, just the html so its easier. codepen.io/Born2Code1983/pen/xjvwPjGoodwill
Wouldn't this be exposed if the client opens the devtools?Lonna
This is absolutely not safe for secrets. Anything in .env will be publicly inspectable in dev tools. The only way to handle a value like this that must remain secret on the client side is to proxy the requests through a server that will handle it for you. See ClaudiuCreanga's comment on the accepted answer.Braithwaite
@Ricarda How does it work in production then? How do the production ready code knows where to access the key?Edmundson
@user117829, my thoughts exactly. I think going the encryption way is optimal.Philanthropy
I got caught out by not restarting the local dev server. Was getting undefined back. >Note: You need to restart the development server after changing .env files. source: create-react-app.dev/docs/adding-custom-environment-variablesMadonia
process is not definedUtrillo
V
83

Warning

Unless you're making tutorial applications, don't put secrets such as API keys in client-side source code (e.g., a React app). From Create React App's documentation:

WARNING: Do not store any secrets (such as private API keys) in your React app!

Environment variables are embedded into the build, meaning anyone can view them by inspecting your app's files.

First, create an .env file in the root of your project, i.e., where you would run react-scripts start (or yarn start) outside of your source folder.

Then, add

REACT_APP_WEATHER_API_KEY=123456

Before commit, you should exclude this .env file, so find the .gitignore file and add .env.

The name of the variable needs to begin with REACT_APP_ which protects you from accidentally including secrets with your build.

Don't forget to add .env in the .gitignore file.


To use the environment variables in your code:

const API_KEY = process.env.REACT_APP_WEATHER_API_KEY;

In order to read environment variables after having added them to .env, restart your server.

Valuer answered 9/2, 2018 at 6:25 Comment(23)
How do I import the .env file into my App.js file?Backsight
Oh, sorry. I didn't provide you how to use it. You can use these env variables like this. const API_KEY = process.env.REACT_APP_WEATHER_API_KEY;Valuer
And also I recommend you to read this part of create-react-app document. Using env variablesValuer
Hm, it's not reading the API key. I created a file called .env outside my src folder. Inside that .env file, the only thing I wrote is REACT_APP_WEATHER_API_KEY=123456. And then in my App.js file, I replaced const API_KEY = "123456"; with const API_KEY = process.env.REACT_APP_WEATHER_API_KEY;Backsight
You should restart your application to update your secret.Valuer
It worked, thank you so much I really appreciate it! In my .gitignore file all I have to do is add a line that says .env ?Backsight
Yeah, that's the only thing.Valuer
How is this accepted answer? facebook.github.io/create-react-app/docs/…: WARNING: Do not store any secrets (such as private API keys) in your React app! Environment variables are embedded into the build, meaning anyone can view them by inspecting your app's files.Cirrhosis
@ClaudiuCreanga So whats the solution then? Should we add a node js server in between api keys and browser request? This way, our node server is the only one that holds the api keys and makes third party requests on behalf of the user using secret api keys stored in node js server.Argentina
@Argentina yes, something like an express server that will handle requests. that's the only way.Cirrhosis
@ClaudiuCreanga, hi Claudiu, I read your comments and got interested, is the above way of hiding api keys worthless. Is it true that api keys will be accessed anyways by, say, hackers if we use the above way?Eudemon
@Eudemon yes, if you put the keys in environment variables like in the answer it is really easy for anybody visiting your site to get them.Cirrhosis
@ClaudiuCreanga, I do not have back-end as Node,js. Just react so how is it possible to somehow hide the keys or any other secret info with just react.Eudemon
@Eudemon you can't with react, you need a backend if you have something to hide from the user, like api keys.Cirrhosis
@ClaudiuCreanga, thank you for your kind comments, that was helpful for me, but what is weird is that why the above answer was accepted and has many upvotes as well as answer right below and the method is worthless.Eudemon
@ClaudiuCreanga, sorry Claudiu just last question :), can I use api keys directly right in query strings without the above method since the above method is worthless and it takes time to create .env files more typing ....?Eudemon
@Eudemon you can do that, of course. the method is not worthless because you may have different api keys for development and production. the env files can separate cleanly those api keys...Cirrhosis
If you have a js server just for serving the keys, wouldn't the person be able to just make the request theirselfs and get the keys anyway? I agree it's a extra step, but since someone is with the intention of stealing, just a extra step wouldn't stop from doint it right?Hawkins
I think the main idea isn't fetch secrets from your js server, but use you server like a proxy, when node server makes a call to external resource with your secrets keys and return back all info to your front app.Amandaamandi
This can work safely for Firebase as API keys can be exposed there publiclyCordey
I will add that I use .env to store my public Google reCaptcha V3 keys. Of course, there are private keys that reCaptcha provides, in which .env method should not be used.Winkelman
I have a react netlify app which is connected to my github. The application is working fine in localhost by on live server it is logging an error The user ID is required. The user ID is the secret id that I hided inside .env file. How can I get my secret ids in this case?Yacht
There is no way of hiding a secret key simply because it is required to send it when you fetch, so as soon as you fetch your key is exposed. You don't even have to read the code, just inspect the outgoing HTTP requests. The only solution is to do requests on the server side. To hide secret keys on your server, there are ways to do this, using environment variables for example.Afterdeck
G
37

From the React documentation:

WARNING: Do not store any secrets (such as private API keys) in your React app!

Environment variables are embedded into the build, meaning anyone can view them by inspecting your app's files.

Glottal answered 27/3, 2019 at 10:58 Comment(9)
So what should we do? Store it serverside? At some point the frontend needs to know the api key...At which point anyone can view it. If anybody knows any good articles on this please share.Katharyn
@TrevorWood Yeah store it serverside and do the actual API calls there. The backend should be acting as a proxy for your React app, storing the secrets, making the API calls, and then sending back data. For example in a React / Express app, you could make an Express endpoint to get the weather. You call the endpoint from React, then Express uses an API key to fetch 3rd party weather data before responding so that React can display the data. rockyourcode.com/secret-keys-in-reactFluorescein
@AntoniaBlair The reason for not putting them in the app is so people can't read the build files to view the API key. But couldn't people also extract the API key after loading the website on their client? Either once the frontend has the API Key or when the frontend requests the API Key.Katharyn
@TrevorWood Don't pass the API key to frontend, keep it in the backend where it's secret. Think of it as a partnership where the backend does API calls, but the frontend can ask the backend for data. See comments: hashnode.com/post/…Fluorescein
@TrevorWood A bit hard to find articles explaining it well, but here's an example of a full-stack app with frontend and backend running on different ports: fullstackreact.com/articles/… The backend has a food endpoint that the frontend can use to request food data. You could update an endpoint like that to have the backend call a 3rd party food API to pull out some interesting data (instead of using database data, or hard-coded data), then send that interesting data to the frontend.Fluorescein
@AntoniaBlair but at some point the frontend needs to know where to look. Other people will also know where to look. I feel like it's extra work that is, in the end, bypassable.Katharyn
How is this the answer to the question?Kesha
This means for a React app to go into production, I have to build to applications?Philanthropy
This doesn't answer the question. It was "How do I hide the API key so that I can commit to GitHub?".Dipteran
G
32

Although the question has already been answered by Antonia Blair, I would like to through some more light on some basic rules.

1: Most of the answers are suggesting to make use of the .env file. I would like to make it clear for once and all that .env is not here to add any security layer. The .env as the name depicts is only here to set up an environment at build time. e.g. by using the environment variables you set some global values at build time and can access these values in your application at runtime.

2: React is simply a framework running your JavaScript code in the client browser. So the client has complete access to the JavaScript (React) code. Nothing is secure on the client-side. So never think of making something secure or hidden from the client by just keeping all your code client-side. Whenever you need to hide something from the client, there is something server-side which you need to incorporate. Only the server-side code is secure from the client-side.

3: So what you do is, you will keep your secure keys on the server-side.

Suppose the purpose of your secure keys is to make a cookie for your client. so the client needs the cookie not the secure keys, right? So the client-side makes a request to the server for a cookie, the server makes the cookie by using the secure keys and returns the cookie to the client. After all the client is only here to eat the cookie and not to know how do we make a cookie right?

4: So the thumb rule is that wherever you have some confidential data, you will keep it on the server. The server will use this confidential data and return the result data to be exposed to the client.

A user has asked for a coding example, so I have put up a real-time scenario which I have handled using the above described technique.

Here is my use case:

  1. I have a React app which submits a public form to non public API.

  2. The non public API is Harvest API hosted by:

    https://www.greenhouse.io/
    
  3. This API requires an authentication header for making requests with it. I have subscribed with the API owner and received a secret token from them which I can use with my requests to get access to their API

  4. Af course, I want to keep my token personal and do not expose it to public users

  5. I have used the Axios client to communicate with the API

I have two ways to perform the above described scenario:

The Incorrect Method

I am making requests to the API directly from my React application

Let’s say below is the API endpoint which I want to hit

apiURL = https://boardsapi.greenhouse.io/v1/boards/xyz/jobs/" + jobId + ""

The above API endpoint requires an authorization header, and I will provide my secret token in it.

const config = {
  headers: {
    "Authorization": "Basic ####MySecretCode#####",
  } };

Suppose I want to post some form data with this request

let formData = MyFormData

I can now send my request using the Axios client like below

let result = await axios.post(apiURL, formData, config);

Using the above technique, I can successfully post my form data to the Harvest API.

But like I said, that it's an incorrect way to communicate with this API. Because I have exposed my secret token on the client side.

The Correct Way

I built an API on Node.js and hosted it publicly.

Suppose I want to post some form data to the Harvest API

let formData = MyFormData

I am not going to hit the Harvest API directly from my client application. And instead I have exposed and endpoint in my middleware API to handle this.

Let’s say the below is the endpoint URL of my middleware API which I want to hit

apiURL = https://proxy-server/apply

The above API endpoint does not requires an authorization header. So I can send a post requests using the Axios client like below:

let result = await axios.post(apiURL, formData);

The difference is clear. I have not supplied the secret token this time in my request. Because this is not a direct request to the Harvest API and instead it's a request to a middle-ware API which is developed and hosted by me.

I receive this request in my middle-ware API, add my secret token with it and forward it to the Harvest API. The response from Harvest API is returned to our middle_ware API and hence forward back to our React client application.

The secret token now resides on my server-side API and safe from external users.

Groos answered 7/4, 2021 at 15:43 Comment(8)
as per number 3 above, any resources, tutorials etc you know of that a new dev could use to learn how to do this?Supersaturate
Perfect answer & easy for a non-technical to understand.Directive
Your method has a security issue of itself: anyone can post to your middle ware endpoint and eventually using your API to access harvest API in your exampleIodoform
@Iodoform that's what I want , anyone to hit my API and I returned to them the results fetched from harvest API. my API is public for everyone. If I wanted to make my API private then there's comes the User Authentication module , through which only the authenticated users can make requests to my APIGroos
If I want to deploy this react app on Netlify, does it mean I have to deploy the api directory too?Mange
@JuJu yes. you can deploy the api anywhereGroos
Can we not use server side rendering in react , so that we can proxy from within the app and then, its not required to deploy the server side API anywhere ?Priory
Fantastic answer! I like this answer in that it simply explains the problems and solution in general terms. Thank you!Hitandmiss
A
6

Here's what worked for me:

I created the .env file in the root folder. Within that folder I added my key:

REACT_APP_API_KEY_YT = "key"
// I added 'YT' for YouTube which is where my API key is from

Then I went to .gitignore. Or create a .gitignore file in your root directory if you don't have it. Within .gitignore, I added .env

# API key
.env

Then I went back to the root of my App js file. For me, that was index.js. For others, it is probably App.js.

There I created a const API_KEY

 const API_KEY =`${process.env.REACT_APP_API_KEY_YT}`

I checked if it was working by console logging it.

 console.log("API", API_KEY)

I was getting undefined.

I stopped the server (Ctrl + C) and restarted the server.

Afterwards I was able to see the key.

Armful answered 10/6, 2018 at 21:6 Comment(1)
.env file save will not cause the react project to be reloaded like saving a .js file. If changes are made to the .env file, you need to CMD+C the bpm or yarn star, then restart it.Anarchic
C
4

Here is an example of finding the API key in code even when you attempt to hide it in an environment variable.

I built a very simple app using the NewsAPI, which required me to register for an API key. Here is my fetch to the NewsAPI endpoint using the API key as an environment variable.

fetch(`https://newsapi.org/v2/top-headlines?q=${keyword}&apiKey=${process.env.REACT_APP_API_KEY}`)
  .then(res => res.json())
  .then(
    (result) => {
      setIsLoaded(true);
      setArticles(result.articles);
    })

However, when I inspected the network request with Chrome dev tools, you will be able to see the actual value of the API key. I hope this helps folks see how somebody could find an API key on the client even if you store it as an environment variable.

Inspecting API keys in network request

How one could hide an API key:

You could make the HTTP request from your server side logic, so you can safely hide an API key in the .env file. In the below example I created an enpoint to /top-headlines/:searchTerm. Once a request to that endpoint is received, then I send the Axios request to the news API using the "NEWS_API_KEY" environment variable which is stored in my .env file.

route.get("/top-headlines/:searchTerm", async (req, res) => {
      const { searchTerm } = req.params;

      try {
        const articlesResponse = await axios.get(
          `https://newsapi.org/v2/top-headlines?q=${searchTerm}&apiKey=${process.env.NEWS_API_KEY}`
        );

        const articlesData = articlesResponse.data;

        res.send(articlesData);
      } catch (error) {
        console.log(error);
      }
    });
Conferva answered 24/6, 2021 at 15:15 Comment(2)
Doesn't answer the question at all.Heaney
This gives an example of how not to hide a secret, but not how to (or whether you even can) hide a secretDilisio
S
3

Be advised! If you put any credentials in a React client, they are not secure, even if you are using gitignore and an .env file. Still they are not secure.

You should really only save API keys or secrets in your backend, such as Node.js or Express.js. Use a proxy, send the request from the front end to the backend and then the backend will make a request for fetching data to front end.

If you are in production, then you cannot use environment variable directly there for frontend (React). You need to follow the instructions on How to implement runtime environment variables with create-react-app, Docker, and Nginx in order to achieve this goal if you want to access environment variables in production.

Salpiglossis answered 4/8, 2022 at 9:55 Comment(0)
S
1

If you use the API key for local development purposes, put it under the .env.development file and Git ignore it. Credentials in the .env file will be picked up by the build process, which will expose the data in production.

For details, see What other .env files can be used?

Scifi answered 21/12, 2019 at 7:50 Comment(0)
H
1

follow these steps :

  1. Install env-cmd package from npm (npm i env-cmd)

  2. Make file .env in your root

  3. Inside the .env file , add varibles with prefix (REACT_APP)

    eg : REACT_APP_APIKEY="yourapikeyhere"

  4. go inside package.json and change the "scripts" as

    "scripts": {

     "start": "env-cmd -f .env react-scripts start",
     "build": "env-cmd -f .env react-scripts build",
     "test": "react-scripts test",
     "eject": "react-scripts eject"
    

    }

  5. use the variable as key = process.env.REACT_APP_APIKEY

Note: After each modification in env file, stop the server and start it again, otherwise it wont read your new changes.

Harrisonharrod answered 5/8, 2023 at 18:44 Comment(0)
H
0

The secure key/secret should never be sent to the client side. Say, you want to download a file from S3 down on the client machine via your app (running in a browser).

  • Make a call to the server to obtain a ephemeral token (which expires with time)

  • the server (which has the secret and everything) makes the token and sends it back

  • the client uses the token to access S3

The token itself is not a secret and it's useless once it expires.

Hitchhike answered 8/9, 2021 at 3:59 Comment(0)
A
0

No answer helped me, rather I figured on my own. For the latest React 18.2.0 you will have to name all the env variables like:

REACT_APP_VARIABLE

This is the only working format, and make sure you globally install dotenv.

Good luck!

Antiperistalsis answered 15/2, 2024 at 18:15 Comment(0)
W
-3

Creating a .env file is helpful as stated in previous answers. But one point to notice here is that:

If you are using API_KEY in your URL as state like this,

this.state = {
         url:`http://newsapi.org/v2/everything&apiKey=${process.env.REACT_APP_API_KEY}`
}

then it will be visible in React developer tool.

Instead, you can put your API_KEY directly at the location of fetch. For example,

fetch(`http://newsapi.org/v2/everything?&apiKey=${process.env.REACT_APP_API_KEY}`)
Wiggle answered 21/8, 2020 at 10:12 Comment(3)
This sort of variables and their values, are visible inside the bundle? I was searching in the static files generated by npm run build and i didn't find anything about it.Kalgan
lol it can also be inspected in the network tab in inspect element consolePigmentation
This is not secure, it just changes the location where it can be found. It's not in project files but it's in built code that is served to client.Trine

© 2022 - 2025 — McMap. All rights reserved.