Firebase config in an APK: what's public and what protects data
Updated
Decompile almost any Firebase app and you will find its API key, project ID and
app ID in plain text, copied from google-services.json into the app's
resources. People find this, panic, and ask whether they have leaked something.
Usually, no. Firebase's documentation says API keys for Firebase services "are not used to control access to backend resources", and that keys restricted to Firebase services "do not need to be treated as secrets". The real risk is somewhere else, and it is worth ten minutes to check.
Why is the key public in the first place?
Your app needs it to talk to Firebase, and anything your app has, anyone with the APK has. That is true of every client app. See how to check your APK for leaked keys for the keys where being public is a problem.
What actually protects your data?
In Firebase's words: "Security of your Realtime Database, Cloud Firestore, and Cloud Storage data is enforced using Firebase Security Rules, and protection of covered APIs is by Firebase App Check — not by keeping your Firebase API key secret."
- Security Rules decide who may read or write each path or document. They are the lock.
- App Check helps covered Firebase services accept requests only from your genuine app, which stops scripts that simply copied your config.
Are your Security Rules open?
The rules to look for are the ones that allow everything:
allow read, write: if true;
Firebase's warning next to that line is: "NEVER use this ruleset in production; it allows anyone to overwrite your entire database." Its explanation of why: without authentication and rules, "anyone who guesses your project ID can steal, modify, or delete the data." Your project ID is in your APK, so nobody has to guess.
Test-mode rules, which allow everything until a date, are the same thing with a timer. Replace them before launch.
What should the rules say instead?
Tie access to the signed-in user. Firebase's example of owner-only access for Firestore:
allow read, delete: if request.auth.uid == resource.data.author_uid;
And for data that everyone may read but only its author may write:
allow read: if true;
allow write: if request.auth.uid == request.resource.data.author_uid;
At minimum, nothing should be writable by a request with no request.auth.
Check Cloud Storage rules as well as the database: uploads are where open rules
cost money.
Is your key restricted to Firebase?
Firebase restricts the keys it creates for you to Firebase-related APIs. Two things undo that:
- Adding other APIs to the same key. Firebase warns: "never include the Gemini Developer API in the allowlist for a publicly accessible API key or a key used for other services."
- Reusing it for Google Cloud APIs. For any Google Cloud API that is not a Firebase service, Firebase "strongly recommends" separate, restricted keys.
If your app calls Gemini directly with a key, that key "should never be included in your code or configuration files." Put the call behind a server that holds the key.
A quick check before launch
- Rules: no
if trueon writes, no test-mode expiry, auth checks on every path. - App Check: turned on for the Firebase services you use.
- Keys: the key in the app is restricted to Firebase services and nothing else.
This is part of the Google Play pre-launch checklist. Google does not review your Firebase rules, so nobody else will check them for you.