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";
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.
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 {
...
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.
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.
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:
I have a React app which submits a public form to non public API.
The non public API is Harvest API hosted by:
https://www.greenhouse.io/
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
Af course, I want to keep my token personal and do not expose it to public users
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.
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.
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.
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);
}
});
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?
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.
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.
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}`)
Related
I was happy lasts days using **.env **file with the npm dotenv package and saving there some secret keys i use on my React App...
On my first test opload I noticed that my webbApp runs ok EVEN without specifying the .env secret keys on the sever...
So then, was obious to feels like the secret keys are anywhere on the public files (and yes)
I was looking what im doing wrong, and found many documentation (official) that says literally:
WARNING: Do not store any secrets (such as private API keys) in your React app!
Environment variables are embedded into the build, anyone can view them by inspecting your app's files.
official doc here if anyone is looking for more info
After 3 or 4 heartAttacks I write this to ask for help on this concept problem.
Anyone knows some documentation where i can read and understant HOW to correctly save sercret keys on this kind of apps (react apps) ?
why the hell is not like all time backend .env files ?
Some info I found, says something about to serve the secret key ontime from another server.
And... sounds stupid for me, i mean: Ok, i can do that but.. its just stupid cause then:
or server will serve the sercret keys "free" vía GET or something like this without no-login-needed.
or webbApp would need a secret_login_key to login and get the secret key <- in this case, where to store that secret_login_key ? its a infinite bucle ? XD
So:
it is posible.. (of course it is) so TRULY store secret keys on React App ? but where and how ?xD
what's the way you store the secret keys on ur react App and u are proud of it?
of course the login typing from keyboard user/pass its the "easyway" to have or not have access tho private information but.. what if i need this to be automatic from my webApp ?
Thanks.
For automatic access to your webapp from the frontend (React), you need a bearer token that is stored in localstorage (bad idea) or as a cookie of the user's browser. Popular example of bearer token is JWT token.
This is how you generate a bearer token on the user's browser: by using Universal Login (login with Google/Fb/Github/Twitter etc) to a provider like Auth0.
React has to communicate with Auth0, Auth0 will authorise the user and return a bearer token that is stored in localstorage (bad idea)/cookie of the browser.
This is what you are trying to do:Call a protected API from React
This is the walk through example of how to do it: Basic Authentication Quick React Setup
Here are some example use cases with different application architecture scenarios:Application Architecture Scenarios
React's documentation is correct, secrets should not be used directly in the React project. But the problem is how to ensure only authorised users get access to protected paths. One way is to use username and password login but you said its the "easyway" and you need it to be automatic. So another way is to ensure authorisation by bearer token stored in localstorage(bad idea)/cookie of the user's browser - this creates a new problem: how to generate a bearer token to allow access. The solution is to use universal login by Auth0 (or Oauth, or OpenID, or Google Authenticator, or some other token generator that the user can possess (like a mobile app (Google Authenticator) or a hardware token)).
Sensitive data should not be on the frontend, you can use env for information like API_URL but not for tokens and passwords
Here is the possible ways to get sensitive data in the frontend
Http call to the backend where secrets are hashed
Http call to an external secret management tool like HashiCorp Vault
Use of httpOnly cookie that they couldn't be read from the frontend
If you are scripting user and password, you should try a tool like jscrambler to secure your build js files
When API calls are made from the frontend (i.e. your react app) anyone using your app can see the request that was made (with tokens, keys, etc.). You should always secret vars to an .env file and keep this file only on your local machine.The best way to handle this, in my opinion, is to use a framework like next or remix that allow you to create functions/api routes that run on the server. This way your frontend makes a request (no sensitive info there) to your server that has access to your keys/tokens. The real call to an external API will be made from the server (so users won't have access to any sensitive data). Not sure if this is something you're interested in but I feel like it's the best way to deal with API calls.
I suggest creating a ".env" to store all your secret keys.
In your ".env" file you can make this one
Eg:
REACT_APP_API_KEY=5155645fdsffsdfs
And in your component, you'll call it
Eg :
const apiKey = process.env.REACT_APP_API_KEY
Let's say I put sensitive information in the file .env.local, for example an external API Key/Secret (and include .env.local in .gitignore). Then, I make reference to this sensitive info in getStaticProps or getServerSideProps.
As the code in getStaticProps or getServerSideProps is run server side, does that mean it is not accessible from the browser ?
Or will data from .env.local file be available to anyone from the browser ?
If the only part of your app that uses env variables runs server side (getStaticProps, getServerProps, getStaticPaths, or anything inside pages/api) the browser cannot access them, so your keys are safe. The client can only see the request it makes to the server and not the request your server makes to other APIs.
I have a react native app (chat) template which I cant figure out how to set it up, don't know if am to get an api key from cometchat or use firebase. The template has been preconfigured I think and by adding firebase credential in the env. the login and register page works, but the chat section is blank.
This is what the documentation says:[
API Integration
Doot react having fake-backend setup already. you will find all files related to API integrations in the src/API folder.
src/apiCore.ts file contains axios setup to call server API(s) including get, put, post, patch, delete, etc methods, interceptors & token set methods.
src/index.ts file contain all module's API call functions which are exported from each module's individual .ts file, E.g. contacts.ts, bookmarks.ts etc.
src/urls.ts file contain all module's API's url.
Note : we have added a Fake backend setup just for user interactions, but if you are working with the real API integration, then there is no need of fake backend as well as the fakeBackend file located in src/helpers/fakeBackend.ts, so you can delete it and also remove the code related to fakeBackend from app.tsx file. you just need to update API's url of the related module from src/apiCore/urls file, that's it!}
The chat interface after login:
App documentation:
App documentation:
I am moving my app from Svelte SPA (original) to Sveltekit multi page app (new).
In the original app, I configure a http client up top and put it context using:
setContext(HTTP_CLIENT, httpClient)
Now the entire app can get that http client using
const httpClient = getContext(HTTP_CLIENT)
I do this because my app can be started with debug parameters than turn on http request logging.
I'm not clear how to do similar in Sveltekit, because it seems that pages do not share a context.
I tried sticking the http client in the session like this:
import { session } from "$app/stores";
$session.httpClient = httpClient
and I got:
Error: Failed to serialize session data: Cannot stringify arbitrary non-POJOs
So $session is meant to be serialized, ok. Does that mean that I need to put whatever debug parameters a user supplied in $session, and each page needs to freshly instantiate its own http client? Or is there some other idiomatic sveltekit way of doing this?
PS I know sveltekit has its own fetch so you might want to say "don't use your own http client", but my app uses many different service objects (graphql client for example) that can be configured in debug (and other) modes, so please don't zero in on the fact that my example is a http client.
One way around this could be to send down the configuration in the top __layout file, create the http client there and store in a store. Since stores are shared across all pages the client can then freely use this store.
I am currently working on a single page react app. This app will not require any login and it will be publicly available.
I am making a POST request to a webhook of another API that I do not have access to and that I do not maintain. This API required me to send an authentication token via the POST. I wonder how I can securely store this token so that it does not get out in the world. I need to send it as is so storing it in a cookie that a backend provides is not an option. Storing in in JWT will not work as I can decode that without the secret.
Is there even a way to store the token without exposing it to the world?
I hope the issue is clear, if not let me know and I'll explain better.
Thank you all for your time!
I would usually have a local Express server running and proxy the request through that.
You would set up a route in your Express app that you would POST to from your React front-end, this Express route handler then makes the call to the external API from the server side which has the token to put in the header. Then the response is returned to your React front-end without it knowing anything about the external API or tokens.
You can't store the token in front-end. either you need to use
cookies/session to store the token. If you want to store the token you
need to encrypt it and store it will be the better option.
Please check here to understand the JWT token mechanism
if the web app doesn't have a login. you can't generate token without user details.
The token should be passed in the header of the request for best practices.
If you're using create-react-app to instantiate your React project, have you looked into using an environment variable to store the token? It's not 100% safe and secure, check here for the cons, but can be a quick fix without a separate proxy request. You can make an .env file (make sure to add it to your .gitignore if using git) in the root of your directory and define variables there. They need to start with REACT_APP, like REACT_APP_SECRET=1234 and can then be referenced where you need them in your app with process.env.REACT_APP_SECRET.
Read more about environments in React here.