[{"data":1,"prerenderedAt":468},["ShallowReactive",2],{"blog-guides/firebase":3},{"id":4,"title":5,"body":6,"category":448,"date":449,"dateModified":449,"description":450,"draft":451,"extension":452,"faq":453,"featured":451,"headerVariant":454,"image":453,"keywords":453,"meta":455,"navigation":456,"ogDescription":457,"ogTitle":453,"path":458,"readTime":459,"schemaOrg":460,"schemaType":461,"seo":462,"sitemap":463,"stem":464,"tags":465,"twitterCard":466,"__hash__":467},"blog/blog/guides/firebase.md","Firebase Security Guide: Firestore Rules and Authentication",{"type":7,"value":8,"toc":422},"minimark",[9,16,21,24,53,62,66,71,74,89,98,102,111,115,119,128,132,141,145,154,158,167,171,175,178,183,186,189,192,195,198,201,205,214,223,227,230,239,243,246,250,259,263,266,281,285,363,391,410],[10,11,12],"tldr",{},[13,14,15],"p",{},"Firebase security depends on Firestore Security Rules (or Realtime Database Rules). Without proper rules, anyone can read and write your data. The Firebase config object is safe to expose, but your security rules are what actually protect your data. Write rules that verify user identity with request.auth, validate data structure, and test thoroughly before deploying.",[17,18,20],"h2",{"id":19},"firebase-security-model","Firebase Security Model",[13,22,23],{},"Firebase lets your frontend talk directly to the database. Security is enforced through rules that run on Firebase's servers, not your code. Understanding this is essential:",[25,26,27,35,41,47],"ul",{},[28,29,30,34],"li",{},[31,32,33],"strong",{},"Config is public:"," Your Firebase config (apiKey, etc.) can be in your frontend code",[28,36,37,40],{},[31,38,39],{},"Rules are your security:"," Security rules determine what users can access",[28,42,43,46],{},[31,44,45],{},"Client-side code is untrusted:"," Never rely on frontend code for security",[28,48,49,52],{},[31,50,51],{},"Authentication provides identity:"," Rules use auth state to make decisions",[54,55,56],"info-box",{},[13,57,58,61],{},[31,59,60],{},"Key concept:"," The Firebase API key is not a secret. It's like a project identifier. Your Firestore Security Rules are what actually protect your data.",[17,63,65],{"id":64},"firestore-security-rules-basics","Firestore Security Rules Basics",[67,68,70],"h3",{"id":69},"the-danger-of-test-mode","The Danger of Test Mode",[13,72,73],{},"When you create a Firebase project, you might start in \"test mode\" which allows all access:",[75,76,78],"code-block",{"label":77},"DANGEROUS: Test mode rules (allow all)",[79,80,85],"pre",{"className":81,"code":83,"language":84},[82],"language-text","rules_version = '2';\nservice cloud.firestore {\n  match /databases/{database}/documents {\n    match /{document=**} {\n      // This allows ANYONE to read and write EVERYTHING\n      allow read, write: if true;\n    }\n  }\n}\n","text",[86,87,83],"code",{"__ignoreMap":88},"",[90,91,92],"danger-box",{},[13,93,94,97],{},[31,95,96],{},"Never deploy with test mode rules."," This is equivalent to having no security at all. Anyone who finds your Firebase project can read, modify, or delete all your data.",[67,99,101],{"id":100},"basic-secure-rules","Basic Secure Rules",[75,103,105],{"label":104},"Secure starting point",[79,106,109],{"className":107,"code":108,"language":84},[82],"rules_version = '2';\nservice cloud.firestore {\n  match /databases/{database}/documents {\n    // Deny all by default\n    match /{document=**} {\n      allow read, write: if false;\n    }\n\n    // Users can only access their own document\n    match /users/{userId} {\n      allow read, write: if request.auth != null\n                         && request.auth.uid == userId;\n    }\n\n    // Public posts are readable, authors can write\n    match /posts/{postId} {\n      allow read: if resource.data.published == true;\n      allow create: if request.auth != null;\n      allow update, delete: if request.auth != null\n                            && request.auth.uid == resource.data.authorId;\n    }\n  }\n}\n",[86,110,108],{"__ignoreMap":88},[17,112,114],{"id":113},"common-security-rules-patterns","Common Security Rules Patterns",[67,116,118],{"id":117},"pattern-1-user-owned-data","Pattern 1: User-Owned Data",[75,120,122],{"label":121},"Users can only access their own documents",[79,123,126],{"className":124,"code":125,"language":84},[82],"match /profiles/{userId} {\n  allow read, write: if request.auth != null\n                     && request.auth.uid == userId;\n}\n\n// For subcollections owned by users\nmatch /users/{userId}/notes/{noteId} {\n  allow read, write: if request.auth != null\n                     && request.auth.uid == userId;\n}\n",[86,127,125],{"__ignoreMap":88},[67,129,131],{"id":130},"pattern-2-data-validation","Pattern 2: Data Validation",[75,133,135],{"label":134},"Validate data on write",[79,136,139],{"className":137,"code":138,"language":84},[82],"match /posts/{postId} {\n  allow create: if request.auth != null\n    // Validate required fields exist\n    && request.resource.data.keys().hasAll(['title', 'content', 'authorId'])\n    // Validate title length\n    && request.resource.data.title.size() \u003C= 200\n    // Validate authorId matches the user\n    && request.resource.data.authorId == request.auth.uid\n    // Validate content is a string\n    && request.resource.data.content is string;\n}\n",[86,140,138],{"__ignoreMap":88},[67,142,144],{"id":143},"pattern-3-role-based-access","Pattern 3: Role-Based Access",[75,146,148],{"label":147},"Check user roles from a separate document",[79,149,152],{"className":150,"code":151,"language":84},[82],"// Helper function to check admin status\nfunction isAdmin() {\n  return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 'admin';\n}\n\nmatch /adminData/{docId} {\n  allow read, write: if request.auth != null && isAdmin();\n}\n\nmatch /users/{userId} {\n  // Users can read their own data\n  allow read: if request.auth != null && request.auth.uid == userId;\n  // Only admins can write to any user\n  allow write: if request.auth != null && isAdmin();\n}\n",[86,153,151],{"__ignoreMap":88},[67,155,157],{"id":156},"pattern-4-time-based-rules","Pattern 4: Time-Based Rules",[75,159,161],{"label":160},"Prevent rapid writes (rate limiting)",[79,162,165],{"className":163,"code":164,"language":84},[82],"match /comments/{commentId} {\n  allow create: if request.auth != null\n    // Check if user has commented recently (basic rate limit)\n    && (!exists(/databases/$(database)/documents/userMeta/$(request.auth.uid))\n        || get(/databases/$(database)/documents/userMeta/$(request.auth.uid)).data.lastComment\n           \u003C request.time - duration.value(30, 's'));\n}\n",[86,166,164],{"__ignoreMap":88},[17,168,170],{"id":169},"firebase-authentication-security","Firebase Authentication Security",[67,172,174],{"id":173},"secure-sign-up-configuration","Secure Sign-Up Configuration",[13,176,177],{},"Configure authentication properly in Firebase Console:",[179,180,182],"h4",{"id":181},"authentication-security-checklist","Authentication Security Checklist",[13,184,185],{},"Enable only the auth providers you actually use",[13,187,188],{},"Set password requirements (length, complexity)",[13,190,191],{},"Enable email verification for email/password auth",[13,193,194],{},"Configure authorized domains (don't allow all)",[13,196,197],{},"Set up proper OAuth redirect URLs",[13,199,200],{},"Review and limit sign-up rate if needed",[67,202,204],{"id":203},"custom-claims-for-authorization","Custom Claims for Authorization",[75,206,208],{"label":207},"Set custom claims (server-side)",[79,209,212],{"className":210,"code":211,"language":84},[82],"// In Cloud Functions or Admin SDK\nconst admin = require('firebase-admin');\n\n// Set admin claim for a user\nawait admin.auth().setCustomUserClaims(userId, { admin: true });\n\n// The claim will be available in security rules:\n// request.auth.token.admin == true\n",[86,213,211],{"__ignoreMap":88},[75,215,217],{"label":216},"Use custom claims in rules",[79,218,221],{"className":219,"code":220,"language":84},[82],"match /adminOnly/{docId} {\n  allow read, write: if request.auth != null\n                     && request.auth.token.admin == true;\n}\n",[86,222,220],{"__ignoreMap":88},[17,224,226],{"id":225},"cloud-storage-security-rules","Cloud Storage Security Rules",[13,228,229],{},"Firebase Storage also needs security rules:",[75,231,233],{"label":232},"Storage security rules",[79,234,237],{"className":235,"code":236,"language":84},[82],"rules_version = '2';\nservice firebase.storage {\n  match /b/{bucket}/o {\n    // User profile images\n    match /users/{userId}/profile.jpg {\n      allow read: if true;  // Public profile images\n      allow write: if request.auth != null\n                   && request.auth.uid == userId\n                   && request.resource.size \u003C 5 * 1024 * 1024  // 5MB max\n                   && request.resource.contentType.matches('image/.*');\n    }\n\n    // Private user files\n    match /users/{userId}/private/{fileName} {\n      allow read, write: if request.auth != null\n                         && request.auth.uid == userId;\n    }\n\n    // Deny everything else\n    match /{allPaths=**} {\n      allow read, write: if false;\n    }\n  }\n}\n",[86,238,236],{"__ignoreMap":88},[17,240,242],{"id":241},"testing-security-rules","Testing Security Rules",[13,244,245],{},"Firebase provides tools to test your rules before deploying:",[67,247,249],{"id":248},"firebase-emulator","Firebase Emulator",[75,251,253],{"label":252},"Run security rules tests",[79,254,257],{"className":255,"code":256,"language":84},[82],"// Install Firebase CLI\nnpm install -g firebase-tools\n\n// Start emulators\nfirebase emulators:start\n\n// Run tests\nfirebase emulators:exec --only firestore \"npm test\"\n",[86,258,256],{"__ignoreMap":88},[67,260,262],{"id":261},"rules-playground","Rules Playground",[13,264,265],{},"In Firebase Console, use the Rules Playground to simulate requests:",[267,268,269,272,275,278],"ol",{},[28,270,271],{},"Go to Firestore > Rules > Edit rules",[28,273,274],{},"Click \"Rules Playground\"",[28,276,277],{},"Simulate different auth states and operations",[28,279,280],{},"Verify rules allow/deny as expected",[17,282,284],{"id":283},"common-firebase-security-mistakes","Common Firebase Security Mistakes",[286,287,288,304],"table",{},[289,290,291],"thead",{},[292,293,294,298,301],"tr",{},[295,296,297],"th",{},"Mistake",[295,299,300],{},"Risk",[295,302,303],{},"Fix",[305,306,307,319,330,341,352],"tbody",{},[292,308,309,313,316],{},[310,311,312],"td",{},"Test mode in production",[310,314,315],{},"Anyone can read/write all data",[310,317,318],{},"Write proper security rules",[292,320,321,324,327],{},[310,322,323],{},"Trusting client data",[310,325,326],{},"Users can send any data",[310,328,329],{},"Validate all fields in rules",[292,331,332,335,338],{},[310,333,334],{},"Not checking auth",[310,336,337],{},"Unauthenticated access",[310,339,340],{},"Always check request.auth",[292,342,343,346,349],{},[310,344,345],{},"Overly broad rules",[310,347,348],{},"Access to unintended data",[310,350,351],{},"Use specific path matches",[292,353,354,357,360],{},[310,355,356],{},"Storing secrets in Firestore",[310,358,359],{},"Exposure via rules bypass",[310,361,362],{},"Use Cloud Functions for secrets",[364,365,366,373,379,385],"faq-section",{},[367,368,370],"faq-item",{"question":369},"Is my Firebase API key secure?",[13,371,372],{},"The Firebase API key (and other config values) are designed to be public. They identify your project but don't grant access. Your security comes from Firestore Security Rules, not from hiding the config. Don't worry if someone sees your firebase config object.",[367,374,376],{"question":375},"Can I hide my Firebase config?",[13,377,378],{},"You can't truly hide it because it needs to be in your frontend code for Firebase to work. Instead of trying to hide it, focus on writing proper security rules. The config is not a security credential.",[367,380,382],{"question":381},"What's the difference between Firestore rules and Realtime Database rules?",[13,383,384],{},"They use different syntax. Firestore rules use a match/allow syntax and can reference other documents. Realtime Database rules use JSON with .read/.write/.validate. Firestore rules are generally more flexible and powerful.",[367,386,388],{"question":387},"Should I validate data in my app or in security rules?",[13,389,390],{},"Both. Validate in your app for good UX (show errors immediately). Validate in security rules for actual security (server-side enforcement). Never skip rule validation because client-side code can be bypassed.",[392,393,394,400,405],"related-articles",{},[395,396],"related-card",{"description":397,"href":398,"title":399},"Step-by-step tutorial","/blog/how-to/firebase-security-rules","How to Set Up Firebase Rules",[395,401],{"description":402,"href":403,"title":404},"Compare security models","/blog/comparisons/supabase-vs-firebase","Supabase vs Firebase Security",[395,406],{"description":407,"href":408,"title":409},"What can go wrong","/blog/vulnerabilities/security-misconfiguration","Firebase Test Mode Vulnerability",[411,412,415,419],"cta-box",{"href":413,"label":414},"/","Start Free Scan",[17,416,418],{"id":417},"check-your-firebase-security","Check Your Firebase Security",[13,420,421],{},"Scan your Firebase project for insecure rules and misconfigurations.",{"title":88,"searchDepth":423,"depth":423,"links":424},2,[425,426,431,437,441,442,446,447],{"id":19,"depth":423,"text":20},{"id":64,"depth":423,"text":65,"children":427},[428,430],{"id":69,"depth":429,"text":70},3,{"id":100,"depth":429,"text":101},{"id":113,"depth":423,"text":114,"children":432},[433,434,435,436],{"id":117,"depth":429,"text":118},{"id":130,"depth":429,"text":131},{"id":143,"depth":429,"text":144},{"id":156,"depth":429,"text":157},{"id":169,"depth":423,"text":170,"children":438},[439,440],{"id":173,"depth":429,"text":174},{"id":203,"depth":429,"text":204},{"id":225,"depth":423,"text":226},{"id":241,"depth":423,"text":242,"children":443},[444,445],{"id":248,"depth":429,"text":249},{"id":261,"depth":429,"text":262},{"id":283,"depth":423,"text":284},{"id":417,"depth":423,"text":418},"guides","2026-01-21","Complete security guide for Firebase. Master Firestore security rules, secure authentication flows, and protect your Firebase project from common vulnerabilities.",false,"md",null,"blue",{},true,"Learn to properly secure your Firebase project with security rules and best practices.","/blog/guides/firebase","12 min read","[object Object]","Article",{"title":5,"description":450},{"loc":458},"blog/guides/firebase",[],"summary_large_image","_Jqmc0rpAguxtM12eM7JOdwyJoYxVTZNBy1AidqQIu0",1775843918547]