Keep API keys out of your frontend and your repo
An API key in frontend code or a Git commit is a public key. Where secrets belong, how a backend proxy protects them, and what to do the moment one leaks.
An API key is a password for a program. Whoever holds it can spend your quota, read your data or run up your bill. Keys leak in two predictable ways: they are shipped inside frontend code, or they are committed to a repository. Automated scanners find both within minutes.
Anything in the browser is public
A JavaScript bundle is a text file that anyone can download and read. Minification does not hide a key, and neither does an environment variable. Build tools copy public variables, such as those starting with VITE_ or NEXT_PUBLIC_, straight into the bundle.
If a key must stay secret, it cannot be in the frontend.
Put a backend between the browser and the API
The frontend calls your server. Your server adds the key and calls the third party.
// server.js: the key never leaves the server
app.get("/api/weather", async (req, res) => {
const city = String(req.query.city ?? "").slice(0, 80);
const upstream = await fetch(
`https://api.weather.example/v1/current?q=${encodeURIComponent(city)}`,
{ headers: { Authorization: `Bearer ${process.env.WEATHER_API_KEY}` } },
);
res.status(upstream.status).json(await upstream.json());
});
// In the browser: no key anywhere
const weather = await fetch("/api/weather?city=Dhaka").then((res) => res.json());
Add rate limiting and caching to that route. Otherwise it becomes a free relay for anyone who finds it.
Keep keys out of Git
- Put local secrets in a
.envfile and list it in.gitignore. - Commit a
.env.examplethat holds the variable names with empty values. - Turn on secret scanning with push protection in your repository host, or run a scanner such as gitleaks before each commit.
Store them properly in production
Use the secret storage your platform provides, or a dedicated secret manager. Do not bake keys into Docker images, and do not print them in CI logs.
Limit what each key can do
- Least privilege. A key that only reads should not be able to write.
- Restrictions. Where the provider allows it, lock a key to your domains or IP addresses.
- Separation. Use different keys for development, staging and production, and for each service.
- Alerts. Set a quota or a budget alarm, so misuse is noticed in hours and not at the end of the month.
Rotate
Replace keys on a schedule and whenever someone with access leaves the team. If rotation is rare, it becomes frightening. If it is routine, it takes minutes.
If a key leaks
- Revoke it at once. Deleting the commit is not enough. The key lives on in the history, in forks and in the scanners' databases.
- Issue a new key and deploy it.
- Check the provider's usage logs for activity that was not yours.
- Find out how it got there, and add the scanning that would have stopped it.
Keys that are meant to be public
Some keys are designed to appear in client code: a payment provider's publishable key, or a maps key. They are safe only because they are restricted. Apply the domain restrictions and usage limits the provider offers.
For loading configuration correctly, see environment variables in Node.js and Vite.