You are right.
If you pass a private API key with your GET request initiated by client-side javascript, you are exposing the key. And no, there's no way around it if you want to do this client-side (if you are fetching the API from a javascript file that runs on the browser).
That's because by definition HTTP requests messages are composed of textual information encoded in ASCII (as properly explained in this MDN article). All HTTP requests of any protocol are always available to the user of the browser who initiated the request, even if you use HTTPS.
It's important to address that the simple fact of your private API key being present on client-side javascript code makes it insecure - public.
If running server-side javascript is an option for you, something like a Node.js backend server, you can fetch your server fetch("https://yourserver.com/resource")
, and then your server can fetch the API with the private key fetch('https://api.com/?api_key=XXXXX')
. Now your backend server is the middle man (or the black box) responsible for getting the API data without exposing the private key.
You won't be exposing the key because the user only knows about the GET request to your server and the data you choose to return. As well, as you have control over your server, you can choose not to expose your private API key by not serving the file in which it is written.
In Node.js webservers, you usually store your API key in a ".env" file PRIVATE_API_KEY=XXXXXXX
, which is not served. This file is then added to the rules present in .gitignore, to prevent it from being pushed to any public repository. With the help of a node package like dotenv, you can access it on your code as a property of the process.env object process.env.PRIVATE_API_KEY
(some examples in their npm page).