How to protect API Keys in React projects using Gateweaver
Gladwin
Posted on April 28, 2024
APIs are essential in modern web development as they enable developers to integrate external data into their applications. However, when using APIs, developers must be cautious when handling API keys. These keys authenticate requests to an API, and if they fall into the wrong hands, they can be used to make unauthorized requests and potentially incur costs or expose sensitive data.
While some API keys, like those for Google Maps, can be safely used in client-side applications due to restrictions that limit their use to specific apps, many should never be exposed to the client and should be handled securely on the server side.
For applications without a dedicated server component, developers can use an API Proxy to securely make API calls while hiding their API keys from the client. An API Proxy acts as an intermediary between the client and the external API, allowing developers to make requests to the Proxy, which then forwards the requests to the external API with the necessary authentication. This way, the API key is never exposed to the client, and developers can safely make requests to the external API.
In this article, we explore how to protect API keys in React projects using Gateweaver, an open-source API Proxy designed to help developers securely manage API keys and sensitive data.
The complete source code for this guide is available on GitHub.
Set up the React App
Create a new React app using Vite
First, let's create a new react app using vite. We'll be using vite's typescript template for this tutorial.
npm create vite@latest react-app -- --template react-ts
Start the React development server
Next, navigate to the newly created react-app
folder and start the development server.
cd react-app
npm install
npm run dev
You should now see the react app running on http://localhost:5173.
Set up Gateweaver
Install Gateweaver CLI
Next, let's install the Gateweaver CLI tool, which we will use to configure and run the API Proxy.
npm install -D @gateweaver/cli
We install the CLI tool as a dev dependency as we only need it during development. For production, you will most likely want to use the Gateweaver Docker image. You can find out more about deploying Gateweaver to production in the Deployment Documentation.
Configure Gateweaver
Next, let's create a folder called proxy
in our project where we will store our Gateweaver configuration files.
mkdir proxy
Inside the proxy
folder, create a new file called gateweaver.yml
. This file will contain the configuration for our API Proxy.
policyDefinitions:
cors:
origin: "${CLIENT_URL}"
endpoints:
- path: "/example"
target:
url: "https://httpbin.org/bearer"
request:
headers:
Authorization: "Bearer ${API_KEY}"
policies:
- cors
In this configuration file, we define an endpoint /example
that proxies requests to https://httpbin.org/bearer. Httpbin is a simple HTTP request and response service that can be used for API testing. We use the httpbin /bearer
endpoint, which requires an Authorization
header with a Bearer
token. We use the ${API_KEY}
syntax to reference an environment variable that will contain our API key to authenticate requests to the httpbin API. We also define a CORS policy that allows requests from ${CLIENT_URL}
.
Add server environment variables
To define the environment variables referenced in the configuration file, we can create a .env.gateweaver
file in the proxy
folder. Make sure to add this file to your .gitignore
file to avoid committing sensitive data to your repository.
API_KEY=example-api-key
CLIENT_URL=http://localhost:5173
In this file, we define the API_KEY
environment variable with our example API key and the CLIENT_URL
environment variable with the URL of our react app.
Start the Gateweaver development server
Before we start the Gateweaver development server, let's add a script to the package.json
file to make it easier to run the server.
{
"scripts": {
"proxy": "cd proxy && gateweaver start -w"
}
}
This script changes the directory to the proxy
folder and runs the gateweaver start -w
command, which starts the Gateweaver development server in watch mode on port 8080.
Now, let's start the Gateweaver development server by running the following command:
npm run proxy
You should be able to test the /example
endpoint by making a request to http://localhost:8080/example. The request will be proxied to https://httpbin.org/bearer with the Authorization
header set to the API key defined in the .env.gateweaver
file. The response should be the following JSON:
{
"authenticated": true,
"token": "example-api-key"
}
Update the React app to use the API Proxy
Now that we have set up Gateweaver, let's update our React app to use the API Proxy to make requests to https://httpbin.org/bearer without exposing the API key to the client.
Add client environment variables
First, let's add the proxy URL as an environment variable in our react project. To do this in a Vite project, we can create a .env.local
file in the root of our project and add the following line:
VITE_PROXY_URL=http://localhost:8080
Make sure to also add this file to your .gitignore
file.
Update the React app
Next, let's update the App.tsx
file to make requests to the API Proxy. We will add a button that fetches data from the Proxy's /example
endpoint and display the response on the page.
import { useState } from "react";
import "./App.css";
interface ProxyResponse {
authenticated: boolean;
token: string;
}
function App() {
const [proxyResponse, setProxyResponse] = useState<ProxyResponse | null>(
null,
);
const handleClick = async () => {
if (proxyResponse) {
setProxyResponse(null);
return;
}
try {
const BASE_URL = import.meta.env.VITE_PROXY_URL;
const response = await fetch(`${BASE_URL}/example`);
if (!response.ok) {
console.error("Failed to fetch data");
return;
}
const data = await response.json();
setProxyResponse(data);
} catch (error) {
console.error(error);
}
};
const buttonText = proxyResponse ? "Clear" : "Fetch data";
return (
<>
<h1>React App</h1>
<div className="card">
<button onClick={handleClick}>{buttonText}</button>
{proxyResponse && (
<>
<h4>Response from Proxy:</h4>
<pre>{JSON.stringify(proxyResponse, null, 2)}</pre>
</>
)}
</div>
</>
);
}
export default App;
Now, when you click the button in your React app, it will make a request to the /example
endpoint on the API Proxy. This will forward the request to https://httpbin.org/bearer using the API key defined in the .env.gateweaver
file. Then the response from the httpbin API will be displayed on the page:
Conclusion
In this tutorial, we learned how to protect API keys in React projects using Gateweaver. We set up a simple API Proxy and configured it to proxy requests to an external API. We then used the Proxy to make requests from our React app to the external API without exposing the API key to the client.
Gateweaver provides additional policies such as rate limiting and jwt validation that you can use to further secure your application. You can find out more about Gateweaver and its features in the documentation. There you can also find information on how to deploy Gateweaver to production.
If you have found this tutorial helpful, please consider giving the Gateweaver repo a star!
Posted on April 28, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.