How I Protect API Keys In My Apps Without Paying For A Server
This topic came up recently on a subreddit and there weren’t any good answers so I published my answer. And I thought it might be interesting so I’d like to talk about it some more.
The ‘Common Advice’
So when you google this question what you get is you should put your API key on your server and then you call your server. Good advice, right? But then… how do you secure the API key for your server? It’s just kicking the can down the road.
I think I know what these people mean. I think they’re saying to hide your key behind a good server that will do authentication for you. Something like Firebase or AWS. This way it’s much harder to call the API without permission.
Because if you don’t do that and instead put your API key behind just a random server with no authentication the benefit of putting your API key behind a server is less clear. Although I guess if someone were to search your entire app for calls to, I don’t know, OpenAI.com and you were using GPT then it would be trivial to find. Whereas hiding the call behind a server would make it a little more difficult.
Although it’s not the best strategy. If you had an app that publicly advertised itself as using GPT like my app Litany an attacker could just search for any API call and try them all until they get the one that works. Most apps probably don’t make too many API calls.
Another benefit is you can also revoke your API key and swap it out seamlessly. Can’t do this with just putting the API key in your app. Or can you?
My Method
So eventually I might want to put my API keys behind Firebase cloud functions. But for now I’m not. I’m storing them in my app. And I’m cheating a little. You see I have access to Firestore Remote Config. And I’m actually storing them in there.
It’s not technically a server. Well it is but it’s not running the requests on a server. Only the keys are on the server. This way I can easily swap out the keys if I need to. In fact the app is programmed to automaticlly try refetching from remote config if it gets a permission denied error.
The benefit of this system is that it’s free. I don’t even have to sign up for a paid plan. The problem with firestore cloud functions is you need a paid plan to use it. Apparently it’s still ‘free’ but I’d rather not risk someone hammering my server causing me to pay tons of money for an app that’s not so popular. The downside of this approach is that the API requests aren’t as protected.
I guess you risk someone abusing your Firestore API or someone abusing the other API you’re trying to protect. It’s a catch-22. It’s why I get annoyed whenever someone posts ‘just put it behind your server’. Like what does that even mean?
Oh yeah, and one more thing I do is encode my key in base 64. I guess this will block a trivial attack where you search for ‘sk-’ because OpenAI’s API keys start with sk. Also I don’t know how it’s laid out in memory but I suspect storing keys in remote config also makes it harder.
So there you have it. That’s how I protect my API keys without running the requests on a server: I encode them and store them in remote config. Now this may not be the best way, it’s mostly just an ad hoc solution. So if anyone has any better ideas post them in the comments.
If you liked this article be sure to give it a few claps. Also considering following me on one of my publications: The Rest Of The Story (RSS) or Lost But Coding (RSS). You can do so with my RSS reader Echo available one iOS (and Apple Silicon Macs) and Android.
