4

I quick question!

I have a webapp that only fetches data from an API so i dont have i backend part. My question is where do you keep your API key? Accordingly to React docs you should not store API keys in the app so how do you manage this when you have an webapp that consumes an API and you have to use the API key in your get requests?

Webbie
  • 537
  • 2
  • 10
  • 25
  • Same problem afflicting google maps apis. Full client-side script publicly exposes the api key. In this particular situation, google suggests to restrict the key in combination with other features, like limiting which domain has access to it. Does your API service provider offer domain limitations? – GrafiCode Jul 31 '21 at 20:19
  • Oh ok! hmm i dont really know if they have domain limitation in the docs. The api i use is https://developers.themoviedb.org/ – Webbie Jul 31 '21 at 20:28
  • 1
    I see. This dates back to 2016, but could still be interesting: https://www.themoviedb.org/talk/582744abc3a3683601019dcc – GrafiCode Jul 31 '21 at 20:53
  • this is from 2014, longer thread: https://www.themoviedb.org/talk/52c61af419c2952ac805bc31 – GrafiCode Jul 31 '21 at 20:55
  • Related: [How do I hide an API key in Create React App?](https://stackoverflow.com/questions/48699820/how-do-i-hide-an-api-key-in-create-react-app) – ggorlen Feb 27 '23 at 18:38

4 Answers4

5

Let's do a bit of explanation, so you connect the dots and design it more robustly. There are two (three) places where to store it in the end:

  1. frontend (your React application)
  2. backend (your server)
  3. third-party service

TL;DR: use non-frontend solution + rate limiting to a registered user and have the registration step secured properly (+ captcha).


  1. Frontend

Storing anything on the frontend side is mostly a bad idea, unless you're completely sure you can allow such data to be exposed - constants, names, icons, maybe some URLs so you don't have it hardcoded in the JS files.

Your "compiled" ReactJS (or any other framework) when built is just a slightly mangled (minified/transpiled/etc etc) JavaScript, but for that to work the client has to retrieve it and have it executed in the browser. Therefore before the ReactJS application even starts, there are 1+ requests downloading the JavaScript code and other parts of the application depending on the framework.

Those you can see in the network monitoring tab in any modern browser or simply use Wireshark (unless encrypted, then it's a little bit annoying) or a local proxy if using a less sane browser.

After retrieval you can simply try Ctrl+F or any online deminifier/deobfuscator if you don't know how to do it yourself and you can retrieve the key.

Implications when retrieved

  • I can impersonate you for the service that issues the API key
  • I can lock your key/account by calling too often (just for fun or to retrieve some info)
  • I can use your web for scraping while not needing to pay for the API key (if paid) or to register to such service vendor
  • If it's per-request API key and there's some limitation that would make it cost you money, I can just run some silly while (true) { callYourApi() } via a service to make me anonymous just to make it cost you

Depending on the API key and how serious you intend to approach this problem, you might utilize the .env file for development purposes only. Though you should never ever store an API key in the frontend unless you explicitly have to store it in there (e.g. maps) because it's mostly a very stupid idea and allows anyone to misuse it.

  1. Backend

Your server, if properly configured and secured, will store the key anywhere which isn't accessible by simply path traversing (if in a file) or scraping (if you attempt to retrieve the key to execute on the frontend part).

Therefore the most sane and secure way would be to retrieve the data (of any service) by having either a custom API or a scheduled script collecting the data, which when your frontend gets called will be able to retrieve as pre-rendered or already fetched, thus no key needed for that case.

However! There's a trick to that. If you design your custom API as /api/<key>=123 or /api/<param> and you use that parameter for the original API to filter on frontend, the attacker couldn't care less for the API key because you've already created an API for free and made it public and unsecure.

So GET /yourapi/<my data> and API key for free without even needing to have one displayed.

How to do it safely? Two simple approaches:

pre-rendering data to HTML

You then fetch with frontend and just display - but this one can be scraped, it's just a bit annoying if more complex, but that's it. Server-side rendering sounds nice, but doesn't really work for this case. It should be mostly used to make the frontend fast or to template the views, but never for security purposes as the silver bullet solution (because it doesn't work that way).

rate limiting + CORS + account management

with rate limiting you make sure that a user (preferably you have that API called only after a user is logged in) can call that API only e.g. 10 times within 1 hour and with CORS you make sure it's callable only by your frontend.

It's not a silver bullet either, anybody with a little bit of brain can simply scrape your API locally thus go around CORS, but the rate limit will still hit hard, if you forbid registering more than 1 user from a single IP or if you require a phone number for verification. And add some annoying captcha, so it's problematic to automate for some people.

Still it can be attacked and misused, but it's painful unless you allow the same phone number (or any other ID less comfortable to get / requiring effort to get) to be used multiple times, so it'll make the most incompetent people go away... and the remaining ones, well, they'd play with your website anyway, so have a proper security assessment / harden your server if you maintain it alone.

  1. Third-party

It's like 2., but you don't maintain the "low-level" server part, because the third-party is then managing it for you, you just need to specify conditions under which it'll be called. This applies to Firebase or Supabase which kind of behaves like a separate backend, but can have multiple modules (for FB, 1, 2).

Thus you'd use Firebase functions (or other alternatives), where you'd have your key e.g. even hardcoded and the client (browser) wouldn't have any access to that, add a limit, cors, perhaps some user registration limit and you're kind of done.


Note: Any domain, IP, region, phone number restrictions can be bypassed, so do not rely on them. It's just a mean to require effort when misusing your website for something different than you intended.

  • domain: curl http(s)://yourweb/path -H "Host: spoofed-domain"
  • region or IP: proxy, VPN, Tor, I2P, just somebody else's computer/server + ssh, some random WiFi
  • phone number: can go to a local shop and buy 10 fresh ones if I wanted to
Peter Badida
  • 11,310
  • 10
  • 44
  • 90
2

It's more of a recommendation for them to keep your API keys server-side, and let your web app communicate with your server. Otherwise malicious users could easily steal your API key and use it for whatever.

If you think it isn't much of a security risk if your key gets (scratch that, is) compromised, that's fine then, you can just keep it in your webapp. Really depends on your use case and what that API key is for.

Kelvin Schoofs
  • 8,323
  • 1
  • 12
  • 31
  • O.P. already stated they have no server-side portion (they called it "backend") – GrafiCode Jul 31 '21 at 20:17
  • @GrafiCode That's why the first half of my question talks about it being a recommendation (it's still good practice) and why that is, while the 2nd half mentions how keeping the key in your app can still be done. – Kelvin Schoofs Jul 31 '21 at 20:29
2

The only way to do this without exposing your API keys in your client app is to create a backend and serve the client app from the backend app as stated by Kelvin Schoofs and Peter Badida answers above (or use a third party service such as AWS Credential Vault). I suggest you use Node Express library for a backend as this will handle a lot of the boiler plate code for you. There are plenty of tutorials online for this.

Using a dotenv file as suggested by a few other users will only hide your API code from version sharing tools like Git (because you can ignore the dotenv in gitignore). It is very important that you understand the process of dotenv with a react app. Any user who opens the Dev console in their browser can view your exposed API keys in the static HTML.

sog
  • 493
  • 4
  • 13
1

Create a dotenv file and store all secret and API keys. Make sure to use REACT_APP_ before every variable.

DOCS: https://create-react-app.dev/docs/adding-custom-environment-variables/ dotenv package: https://www.npmjs.com/package/dotenv

kanjurer
  • 43
  • 6