Securing Financial API Keys in Web and Mobile Apps: Proxies, Restrictions and Rotation
Best practices for securing financial API keys: why front-end and mobile apps cannot hide secrets, backend proxies, IP restrictions, rotation and monitoring.

- Anything shipped to a browser or app binary can be extracted; a secret key there is a public key.
- Call the API from your server and expose only your own, cached endpoint to clients.
- Add IP or domain restrictions, rotate keys, monitor usage and scan repositories for leaked secrets.
API keys for financial data are valuable: they carry a quota, sometimes a paid plan, and they identify you. Yet the most common integration mistake is pasting the key into JavaScript or a mobile app. This guide covers securing financial API keys properly — not by obfuscation, but by architecture.
Part of the Iranian Rial exchange rate API guide.
Why client-side secrets fail
| Where you put the key | How it leaks |
|---|---|
| JavaScript bundle | View source, DevTools → Network, the request header itself |
| Environment variable in a front-end build | It is inlined into the bundle at build time |
| Android APK / iOS IPA | Decompilers and string extraction; traffic interception |
| “Obfuscated” string | Reversible; the decoded value is visible in the request anyway |
| Public Git repository | Bots scan new commits for secrets within minutes |
The rule is simple: if the client can send the key, an attacker can read it.
The backend proxy pattern
// Express example
import express from "express";
const app = express();
let cache = { at: 0, body: null };
app.get("/api/rates", async (_req, res) => {
if (Date.now() - cache.at > 60_000) {
const r = await fetch("https://api.ezrate.me/v1/rates?symbols=usd,eur,g18",
{ headers: { "X-API-Key": process.env.EZRATE_KEY } });
if (r.ok) cache = { at: Date.now(), body: await r.json() };
}
if (!cache.body) return res.status(503).json({ error: "unavailable" });
res.set("Cache-Control", "public, max-age=30").json(cache.body);
});
app.listen(3000);Your proxy is also the right place to add your own rate limiting, so a scraper hitting your endpoint cannot drain your upstream quota.
Mobile apps
- The app calls your backend, never the provider directly.
- Authenticate your own users (or use device attestation such as Play Integrity / App Attest) to make abuse of your endpoint harder.
- Cache on the device and refresh at most once a minute.
See the full mobile build in Flutter & React Native FX tracker.
Restrictions, rotation and monitoring
| Control | What to do |
|---|---|
| IP restriction | Allow only your server IPs for the key; requests from elsewhere get 403 forbidden |
| Domain restriction | For browser-origin use cases, restrict to your domains |
| Separate keys | One key per environment and per app; revoke one without breaking others |
| Rotation | Create a new key, deploy it, then delete the old one |
| Monitoring | Check /usage and the X-RateLimit-Remaining-* headers; alert on unusual spikes |
| Secret scanning | Enable GitHub secret scanning or pre-commit hooks (gitleaks) |
# usage does not count against your quota
curl -s -H "X-API-Key: $EZRATE_KEY" https://api.ezrate.me/v1/usage | jqIf a key leaks
- Create a new key in the panel and deploy it.
- Delete the leaked key.
- Remove it from Git history if it was committed (rotation is still required).
- Review usage for the leak period.
No key at all: widgets
For a public ticker or table on a website, EZRate’s embeddable widgets load data without any API key, are cached and include attribution. That is the safest option when you do not need raw data.
US Dollar265,200Toman−0.45%A note on environment variables
Environment variables are the right place for server-side secrets, but in front-end frameworks variables with public prefixes (NEXT_PUBLIC_, VITE_, NUXT_PUBLIC_) are compiled into the browser bundle. Keep financial keys in variables without those prefixes and read them only in server code such as API routes or server middleware.
Related live rates: US dollar rate, 18K gold price, Emami coin price.

Comments (0)
Comments are shown after review. Sign-in is needed to send.


