Is your Firebase app secure?
Firebase is a secure platform, and the API key in your web config is meant to be public. Your app is secure when Firestore, Realtime Database and Storage rules only allow what each user should do, and no service account key or other secret ends up in your front end.
Updated
Check your live site now
Free, no signup, read only. A grade and plain fixes in seconds.
What Firebase secures, and what your rules decide
Firebase runs the database, authentication, file storage and hosting on Google's infrastructure, over HTTPS. Firebase Auth handles passwords and sign-in providers for you.
Your web app talks to Firestore, Realtime Database and Storage directly from the browser, using the config object with apiKey, projectId and so on. That config is not a secret, and Firebase's own docs say so. Access to your data is decided by Security Rules, which you write. If the rules let everyone read, anyone with your project ID can read.
Firebase security mistakes to look for
- Rules still in test mode. Test mode allows all reads and writes until a date, and then the app stops working, which tempts people to extend the date or replace it with allow read, write: if true.
- Rules that only check request.auth != null. Any signed-in user, including one who just made an account, can then read everyone's data.
- Storage rules that let any user read every uploaded file.
- A service account JSON file (with a private_key field) in the front end or in the hosting folder. That key has admin access to your project and ignores rules.
- The API key left unrestricted in Google Cloud, so it can be used for any API enabled on the project.
- Other secrets, such as a Stripe or OpenAI key, called from the browser instead of from a Cloud Function.
Where the fixes go in Firebase
Rules live in firestore.rules, database.rules.json and storage.rules in your project, deployed with the Firebase CLI, or in the Rules tab in the console. Scope each collection to its owner:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId}/{document=**} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
}
}- API key restrictions: Google Cloud console, APIs and Services, Credentials. Restrict the browser key to the APIs your app uses and to your domains.
- Secrets: Cloud Functions with the key stored in Secret Manager, not in the web app.
- Service accounts: server only. If one was public, delete that key in the console and create a new one.
- Headers on Firebase Hosting: a headers array in the hosting section of firebase.json.
Rewrite my Firestore and Storage security rules so each user can only read and write their own documents and files, keyed by request.auth.uid. Remove any rule that allows all access or only checks that the user is signed in. Move any Stripe, OpenAI or other secret key out of the web app into a Cloud Function that reads it from Secret Manager. Add security headers to firebase.json. Show me the rules before deploying.Firebase security checklist
- Open the Rules tab for Firestore, Realtime Database and Storage. No test mode dates and no if true on user data.
- Test the rules in the Rules Playground or the local emulator, as a signed-out user and as a second user.
- Restrict the browser API key in Google Cloud to the APIs and domains you use.
- Search the hosting folder and bundles for private_key, BEGIN PRIVATE KEY and other key prefixes.
- Move any paid API call into a Cloud Function.
- Add security headers in firebase.json and redeploy.
How to check your live Firebase app
You can test your own database the way a stranger would, with no credentials. For Realtime Database, request the root of your database URL (shown at the top of the Data tab; projects outside the US use a firebasedatabase.app address):
curl 'https://YOUR-PROJECT-default-rtdb.firebaseio.com/.json?shallow=true'A permission denied error is what you want. Data means your rules allow public reads. For Firestore, a GET on https://firestore.googleapis.com/v1/projects/YOUR-PROJECT/databases/(default)/documents/users with no auth should also be refused.
An outside scan checks the site itself. It flags a Google API key in your front end as a reminder to confirm it is restricted (it cannot see the restrictions from outside), finds private keys and other secret keys in your HTML and JavaScript bundles, and checks for public .env and .git files, security headers, cookie flags and CORS. It cannot read your Security Rules, so the tests above are how you check them.
Questions
Is it safe to expose my Firebase API key?
Yes. The web config key identifies your project and is meant to be public. Restrict it in Google Cloud anyway, and rely on Security Rules to protect your data.
Is Firebase test mode safe?
No. Test mode rules let anyone read and write your database until the date in the rule. Replace them with real rules before you share the app.
Is request.auth != null enough in my Firebase rules?
Only for data every signed-in user should see. For personal data, compare request.auth.uid to the owner of the document.
What should I do if my service account key was public?
Delete that key in the Google Cloud console right away and create a new one for your server. A service account key bypasses Security Rules.