How do I hide API key in create-react-app?

ReactjsApiGithubCreate React-AppApi Key

Reactjs Problem Overview


I made a weather app in 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";

Reactjs Solutions


Solution 1 - Reactjs

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 @ClaudiuCreanga, 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 / Express. 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.

Solution 2 - Reactjs

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 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 backend is better option and if client wants to access secret data, it can be accessed by making 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 {
...

Solution 3 - Reactjs

WARNING

Unless you're making tutorial apps, don't put secrets such as API keys in client side source code (e.g. 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 src folder.

Then, add

REACT_APP_WEATHER_API_KEY=123456

Before commit, you should exclude this .env file so find .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 .gitignore file.


To to use the env variables in your code:

const API_KEY = process.env.REACT_APP_WEATHER_API_KEY;

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

Solution 4 - Reactjs

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.

Solution 5 - Reactjs

Although the question has already been answered by @Antonia Blair but 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: Reactjs is simply a framework running your javascript code in the client browser. So the client has complete access to the javascript (Reactjs) 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.

Edit Sep_06_2021

A User has asked for a coding example so I will put up a real time scenario which I have handled using the above described technique. Here is my use case

  1. I have a Reactjs 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. Ofcourse I want to keep my token personal and do not expose it to public users

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

I have 2 ways to perform the above described scenario

The Incorrect Method

I am making requests to the API directly from my Reactjs Application

Lets 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 client side.

The Correct Way

I built an API on Nodejs 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. lets say 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 Reactjs client application.

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

Solution 6 - Reactjs

Here's what worked for me:

I created the .env 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 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 other 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 (Control + C) and restarted the server. Afterwards I was able to see the key.

Solution 7 - Reactjs

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

Edit to explain 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);
      }
    });

Solution 8 - Reactjs

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

Detail see https://create-react-app.dev/docs/adding-custom-environment-variables/#what-other-env-files-can-be-used

Solution 9 - Reactjs

Creating an .env file is helpful as stated above. 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}`)

Solution 10 - Reactjs

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.

Solution 11 - Reactjs

A step further besides adding just an .env file is to using dotenv.

  1. Create .gitignore file in the root folder.
  2. Add .env in the .gitignore file
  3. Install dotenv
  4. Require and configure dotenv
    require('dotenv').config()
  1. Create .env in the root folder.
  2. Add enviroment-specific variables in your .env file. Making sure that you have REACT_APP_... or else it will not work!
    REACT_APP_DB_HOST=localhost
    REACT_APP_DB_USER=root
    REACT_APP_DB_PASS=s1mpl3
  1. Use process.env in your app to access keys and values in your .env file.
    const db = require('db')
    db.connect({
      host: process.env.DB_HOST,
      username: process.env.DB_USER,
      password: process.env.DB_PASS
    })
Recommended Api Key Solutions

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionE. ChoiView Question on Stackoverflow
Solution 1 - ReactjsAntonia BlairView Answer on Stackoverflow
Solution 2 - ReactjsrichardsonaeView Answer on Stackoverflow
Solution 3 - ReactjsGomproView Answer on Stackoverflow
Solution 4 - ReactjsTom FoxtrotView Answer on Stackoverflow
Solution 5 - ReactjsumerView Answer on Stackoverflow
Solution 6 - ReactjsRoger PerezView Answer on Stackoverflow
Solution 7 - ReactjsS. VanderlindenView Answer on Stackoverflow
Solution 8 - ReactjsYuming CaoView Answer on Stackoverflow
Solution 9 - ReactjsSiddhant JainView Answer on Stackoverflow
Solution 10 - ReactjsAvinash BhatiaView Answer on Stackoverflow
Solution 11 - ReactjsJGazcaView Answer on Stackoverflow