Have you ever noticed that some applications have API keys, tokens, or other sensitive credentials visible in their source code? or maybe your own applications?
Well, this can be dangerous and put the security of your services at risk.
API keys, tokens, and other sensitive credentials are used to authenticate and authorize access to services and APIs. If this data is exposed in your application’s source code, anyone who can see your code can access it and use it to perform unauthorized actions on your behalf.
Moreover, by exposing your credentials, you are allowing third parties to use them, which can affect the performance or quality of your services, or even perform attacks against them.
This tutorial will show us how to hide your API keys, tokens, and other sensitive credentials.
Some of the ways to do this are:
Use environment variables
Use a proxy server or a backend platform as a service (BaaS)
Use a secure hosting platform
In this way, you can protect the security of your services and prevent them from being compromised. Now, we will see how to hide sensitive credentials by building a small backend for our React application.
Note: This is just the first step, your application will remain vulnerable after this.
In this tutorial, we will add an OpenWeather APY KEY as an environment variable.
Specifically, we will use the weather API, which is a service that provides weather data, and after a certain number of requests, it starts charging for the requests, so we don’t want this API KEY available to the public.
To configure the environment variables in React, with Vite, we can follow these steps:
1 — Create your React application with Vite. I will use TypeScript but you can use JavaScript if you wish.
2 — Create a .env file at the root of your project. This file should contain the environment variables you want to use in your application.
API_KEY=784dc6d4eXXXXXXXXb14460d3a356565
PORT=3001
Once we create our .env
file we must not forget to attach it to the .gitignore
file of git, otherwise, our API KEY will be exposed in the repository.
3— In Vite, to access the environment variables we need to access them via import.meta.env
. This returns an object containing the available environment variables known to Vite.
The variables created must have the prefix VITE_
or could be another prefix overwriting the default configuration option
const API_KEY = import.meta.env.VITE_API_KEY
4 — Now we will create a simple application that will fetch the Weather API to retrieve the temperature of a city.
import { useEffect, useState } from "react"
import { ResponseWeather } from "../types"
const API_KEY = import.meta.env.VITE_API_KEY
import "./App.css"
function App() {
const [weather, setWeather] = useState<ResponseWeather | null>(null)
useEffect(() => {
const options = {
method: "GET",
url: `https://api.openweathermap.org/data/2.5/weather?lat=43.7001&lon=-79.4163&appid=${API_KEY}`)
headers: {
"Content-Type": "application/json",
},
}
axios.request(options).then(response => {
setWeather(response.data)
})
}, [])
if (!weather) return null
return (
<div className='App'>
<h1>{weather?.name}</h1>
<h2>{Math.floor(weather?.main.temp - 273.15)} °C</h2>
<i>
<img
src={`http://openweathermap.org/img/wn/${weather?.weather[0].icon}@2x.png`}
alt={weather?.weather[0].description}
/>
</i>
<p>{weather?.weather[0].main}</p>
</div>
)
}
export default App
Now that we have hidden our API KEY with an environment variable and made sure that the .env
file is not uploaded to the repository, we have done half the work.
UPDATE: although it is not exactly half of the work to keep our application secure it would be all we can do on the client side. Make sure that we don’t save in the repository that is public the keys or sensitive variables for the project. Since it would be another vulnerable access route, it’s possible that someone may not be able to access the application on the web, but may be able to find the repository of the project in some way.
And why do we say this? Because our API KEY is still exposed in the final build. If we inspect our app in the browser we will find the value of the API KEY, so the only way to have this value completely hidden is to have it on the server side creating a backend service.
This backend will be in charge of making requests to the Openweather service and our client, that is, our React application will query this backend.
pnpm express cors dotenv axios
In this case that we use Typescript, we will need in addition
pnpm ts-node @types/express @types/cors @types/dotenv @types/node
2 — We create a file called api.ts
at the root of the project. We also take the opportunity to add a new command to package.json
to boost our server.
"scripts": {
"server": "npx ts-node api.ts",
...
}
3 — We create the server and make available the endpoint that we will use from React.
import express from "express"
import { Request, Response } from "express"
import * as dotenv from "dotenv"
import cors from "cors"
import axios from "axios"
dotenv.config()
const app = express()
app.use(cors())
app.get("/api/weather", (req: Request, res: Response) => {
const options = {
method: "GET",
url: `https://api.openweathermap.org/data/2.5/weather?lat=43.7001&lon=-79.4163&appid=${process.env.VITE_API_KEY}`,
headers: {
"Content-Type": "application/json",
},
}
axios
.request(options)
.then(response => {
res.json(response.data)
})
.catch(err => {
console.log(err)
})
})
app.listen(process.env.VITE_PORT, () => console.log(`Server on port ${process.env.VITE_PORT || 3001}`))
Now that we have the backend service, our API KEY is completely hidden from the client. We could add more layers of security as we want for example, in the cors add only the domain where our app is hosted and only that domain can make requests.
4 — We start our server with the following command
pnpm run server
Finally, we just need to replace the URL of the request we make in React with the one we have in the backend. We no longer need to retrieve the API KEY in React.
// Before
url: `https://api.openweathermap.org/data/2.5/weather?lat=43.7001&lon=-79.4163&appid=${API_KEY}`)
// After
url: "http://localhost:3001/api/weather"
And that’s it! our application continues to work as usual only that we no longer have our API KEY exposed on the client side.
In conclusion, hiding sensitive data is something relatively easy, just follow the steps mentioned above and with that, we can avoid major risks and complications.
I hope this will help you to keep your projects safe.
Also published here.