[{"data":1,"prerenderedAt":398},["ShallowReactive",2],{"blog-how-to/firebase-auth-rules":3},{"id":4,"title":5,"body":6,"category":378,"date":379,"dateModified":380,"description":381,"draft":382,"extension":383,"faq":384,"featured":382,"headerVariant":385,"image":384,"keywords":384,"meta":386,"navigation":387,"ogDescription":388,"ogTitle":384,"path":389,"readTime":384,"schemaOrg":390,"schemaType":391,"seo":392,"sitemap":393,"stem":394,"tags":395,"twitterCard":396,"__hash__":397},"blog/blog/how-to/firebase-auth-rules.md","How to Write Firebase Auth Rules",{"type":7,"value":8,"toc":363},"minimark",[9,13,17,21,27,30,43,48,51,54,58,95,111,127,152,168,193,221,225,253,257,262,265,269,275,279,285,289,295,325,344],[10,11],"category-badge",{"category":12},"How-To Guide",[14,15,5],"h1",{"id":16},"how-to-write-firebase-auth-rules",[18,19,20],"p",{},"Protect your Firebase data with authentication-based security rules",[22,23,24],"tldr",{},[18,25,26],{},"TL;DR (20 minutes):\nUse\nrequest.auth != null\nto require authentication. Use\nrequest.auth.uid == resource.data.userId\nto ensure users only access their own data. Store user roles in custom claims or a separate collection, then check them in rules.",[18,28,29],{},"Prerequisites:",[31,32,33,37,40],"ul",{},[34,35,36],"li",{},"Firebase project with Firestore or Realtime Database",[34,38,39],{},"Firebase Authentication set up",[34,41,42],{},"Basic understanding of Firebase security rules syntax",[44,45,47],"h2",{"id":46},"why-this-matters","Why This Matters",[18,49,50],{},"Firebase security rules are your last line of defense. Even if your frontend code is \"secure,\" anyone can call your Firebase APIs directly. Without proper auth rules, attackers can read all your data, modify other users' records, or delete everything.",[18,52,53],{},"The most common vulnerability in vibe-coded Firebase apps is leaving rules in \"test mode\" - wide open to the public. This guide shows you how to lock things down properly.",[44,55,57],{"id":56},"step-by-step-guide","Step-by-Step Guide",[59,60,62,67,75,85],"step",{"number":61},"1",[63,64,66],"h3",{"id":65},"understand-the-requestauth-object","Understand the request.auth object",[18,68,69,70,74],{},"When a user is authenticated, ",[71,72,73],"code",{},"request.auth"," contains their info:",[76,77,82],"pre",{"className":78,"code":80,"language":81},[79],"language-text","// request.auth structure\n{\n  uid: \"user123\",           // Unique user ID\n  token: {\n    email: \"user@example.com\",\n    email_verified: true,\n    name: \"John Doe\",\n    // Custom claims you've set\n    admin: true,\n    role: \"premium\"\n  }\n}\n","text",[71,83,80],{"__ignoreMap":84},"",[18,86,87,88,90,91,94],{},"If the user is not authenticated, ",[71,89,73],{}," is ",[71,92,93],{},"null",".",[59,96,98,102,105],{"number":97},"2",[63,99,101],{"id":100},"require-authentication-for-all-access","Require authentication for all access",[18,103,104],{},"Start by locking down everything to authenticated users only:",[76,106,109],{"className":107,"code":108,"language":81},[79],"// Firestore rules\nrules_version = '2';\nservice cloud.firestore {\n  match /databases/{database}/documents {\n    // Default: deny all\n    match /{document=**} {\n      allow read, write: if false;\n    }\n\n    // Require authentication for specific collections\n    match /posts/{postId} {\n      allow read: if request.auth != null;\n      allow write: if request.auth != null;\n    }\n  }\n}\n",[71,110,108],{"__ignoreMap":84},[59,112,114,118,121],{"number":113},"3",[63,115,117],{"id":116},"implement-user-owned-data-rules","Implement user-owned data rules",[18,119,120],{},"Ensure users can only access their own data:",[76,122,125],{"className":123,"code":124,"language":81},[79],"rules_version = '2';\nservice cloud.firestore {\n  match /databases/{database}/documents {\n    // User profiles - users can only read/write their own\n    match /users/{userId} {\n      allow read, write: if request.auth != null\n                         && request.auth.uid == userId;\n    }\n\n    // User's private data\n    match /users/{userId}/private/{document} {\n      allow read, write: if request.auth != null\n                         && request.auth.uid == userId;\n    }\n\n    // Orders - users can only see their own orders\n    match /orders/{orderId} {\n      allow read: if request.auth != null\n                  && request.auth.uid == resource.data.userId;\n      allow create: if request.auth != null\n                    && request.auth.uid == request.resource.data.userId;\n    }\n  }\n}\n",[71,126,124],{"__ignoreMap":84},[59,128,130,134,137,143,146],{"number":129},"4",[63,131,133],{"id":132},"add-role-based-access-with-custom-claims","Add role-based access with custom claims",[18,135,136],{},"First, set custom claims in your backend:",[76,138,141],{"className":139,"code":140,"language":81},[79],"// Node.js Admin SDK - set user as admin\nconst admin = require('firebase-admin');\n\nasync function setAdminRole(uid) {\n  await admin.auth().setCustomUserClaims(uid, { admin: true });\n}\n\n// Set premium role\nasync function setPremiumRole(uid) {\n  await admin.auth().setCustomUserClaims(uid, { role: 'premium' });\n}\n",[71,142,140],{"__ignoreMap":84},[18,144,145],{},"Then check claims in your rules:",[76,147,150],{"className":148,"code":149,"language":81},[79],"rules_version = '2';\nservice cloud.firestore {\n  match /databases/{database}/documents {\n    // Admin-only collection\n    match /admin/{document=**} {\n      allow read, write: if request.auth != null\n                         && request.auth.token.admin == true;\n    }\n\n    // Premium content\n    match /premium-content/{docId} {\n      allow read: if request.auth != null\n                  && request.auth.token.role == 'premium';\n    }\n\n    // Public content anyone authenticated can read\n    match /public/{docId} {\n      allow read: if request.auth != null;\n      allow write: if request.auth != null\n                   && request.auth.token.admin == true;\n    }\n  }\n}\n",[71,151,149],{"__ignoreMap":84},[59,153,155,159,162],{"number":154},"5",[63,156,158],{"id":157},"alternative-store-roles-in-firestore","Alternative: Store roles in Firestore",[18,160,161],{},"If you can't use custom claims, store roles in a collection:",[76,163,166],{"className":164,"code":165,"language":81},[79],"rules_version = '2';\nservice cloud.firestore {\n  match /databases/{database}/documents {\n    // Helper function to check admin status\n    function isAdmin() {\n      return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 'admin';\n    }\n\n    // Helper function to check any role\n    function hasRole(role) {\n      return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == role;\n    }\n\n    match /admin-settings/{docId} {\n      allow read, write: if request.auth != null && isAdmin();\n    }\n\n    match /premium/{docId} {\n      allow read: if request.auth != null && hasRole('premium');\n    }\n  }\n}\n",[71,167,165],{"__ignoreMap":84},[59,169,171,175,178,184,187],{"number":170},"6",[63,172,174],{"id":173},"test-your-rules-with-the-emulator","Test your rules with the Emulator",[18,176,177],{},"Use the Firebase Emulator Suite to test rules locally:",[76,179,182],{"className":180,"code":181,"language":81},[79],"# Install and start emulators\nfirebase emulators:start\n\n# Run rules tests\nfirebase emulators:exec \"npm test\"\n",[71,183,181],{"__ignoreMap":84},[18,185,186],{},"Write unit tests for your rules:",[76,188,191],{"className":189,"code":190,"language":81},[79],"// rules.test.js\nconst { assertSucceeds, assertFails } = require('@firebase/rules-unit-testing');\n\ndescribe('Firestore rules', () => {\n  it('allows users to read their own data', async () => {\n    const db = getFirestore({ uid: 'user123' });\n    await assertSucceeds(db.collection('users').doc('user123').get());\n  });\n\n  it('denies users from reading other users data', async () => {\n    const db = getFirestore({ uid: 'user123' });\n    await assertFails(db.collection('users').doc('other-user').get());\n  });\n\n  it('denies unauthenticated access', async () => {\n    const db = getFirestore(null); // No auth\n    await assertFails(db.collection('users').doc('anyone').get());\n  });\n});\n",[71,192,190],{"__ignoreMap":84},[194,195,196,199],"warning-box",{},[18,197,198],{},"Common Mistakes to Avoid:",[31,200,201,208,211,218],{},[34,202,203,204,207],{},"Never leave rules in test mode (",[71,205,206],{},"allow read, write: if true",") in production",[34,209,210],{},"Don't trust client-provided role data - always verify on the server or in rules",[34,212,213,214,217],{},"Remember: ",[71,215,216],{},"get()"," in rules counts as a read operation and affects billing",[34,219,220],{},"Custom claims are cached - users may need to sign out and back in to see changes",[44,222,224],{"id":223},"how-to-verify-it-worked","How to Verify It Worked",[226,227,228,235,241,247],"ol",{},[34,229,230,234],{},[231,232,233],"strong",{},"Firebase Console:"," Go to Firestore → Rules → Run a simulation",[34,236,237,240],{},[231,238,239],{},"Try unauthorized access:"," Use an incognito browser to test unauthenticated requests",[34,242,243,246],{},[231,244,245],{},"Test cross-user access:"," Log in as User A and try to access User B's data",[34,248,249,252],{},[231,250,251],{},"Check the Rules Playground:"," Simulate different auth states in Firebase Console",[44,254,256],{"id":255},"common-errors-troubleshooting","Common Errors & Troubleshooting",[258,259,261],"h4",{"id":260},"error-missing-or-insufficient-permissions","Error: \"Missing or insufficient permissions\"",[18,263,264],{},"Your rules are denying the request. Check that the user is authenticated and has the required role/ownership.",[258,266,268],{"id":267},"custom-claims-not-working","Custom claims not working",[18,270,271,272,94],{},"Claims are cached in the ID token. Have the user sign out and back in, or force a token refresh with ",[71,273,274],{},"user.getIdToken(true)",[258,276,278],{"id":277},"rules-working-locally-but-failing-in-production","Rules working locally but failing in production",[18,280,281,282],{},"Make sure you deployed your rules: ",[71,283,284],{},"firebase deploy --only firestore:rules",[258,286,288],{"id":287},"get-function-returning-null","get() function returning null",[18,290,291,292],{},"The document doesn't exist. Add a null check: ",[71,293,294],{},"exists(/path/to/doc) && get(...).data.field",[296,297,298,305,315],"faq-section",{},[299,300,302],"faq-item",{"question":301},"Custom claims vs. Firestore roles collection - which is better?",[18,303,304],{},"Custom claims are faster (no extra reads) and more secure (can't be modified by clients). Use them for simple roles. Use a Firestore collection when roles are complex, frequently changed, or need to store additional metadata.",[299,306,308],{"question":307},"How do I handle public data that anyone can read?",[18,309,310,311,314],{},"Create a separate collection for public data with ",[71,312,313],{},"allow read: if true"," but still restrict writes to authenticated users or admins.",[299,316,318],{"question":317},"Can I use Firebase Rules with anonymous authentication?",[18,319,320,321,324],{},"Yes, anonymous users still have a ",[71,322,323],{},"request.auth.uid",". You can allow limited access to anonymous users while requiring full authentication for sensitive operations.",[18,326,327,330,335,336,335,340],{},[231,328,329],{},"Related guides:",[331,332,334],"a",{"href":333},"/blog/how-to/firebase-security-rules","Firebase Security Rules"," ·\n",[331,337,339],{"href":338},"/blog/how-to/firebase-auth","Firebase Auth Setup",[331,341,343],{"href":342},"/blog/how-to/setup-supabase-rls","Supabase RLS Setup",[345,346,347,353,358],"related-articles",{},[348,349],"related-card",{"description":350,"href":351,"title":352},"Step-by-step guide to using parameterized queries to prevent SQL injection. Examples for PostgreSQL, MySQL, MongoDB, and","/blog/how-to/parameterized-queries","How to Use Parameterized Queries",[348,354],{"description":355,"href":356,"title":357},"Step-by-step guide to implementing secure password reset flows. Prevent account takeover, token attacks, and enumeration","/blog/how-to/password-reset-security","How to Implement Secure Password Reset",[348,359],{"description":360,"href":361,"title":362},"Step-by-step guide to PostgreSQL role-based access control. Create users, assign permissions, and implement least-privil","/blog/how-to/postgresql-roles","How to Set Up PostgreSQL Roles and Permissions",{"title":84,"searchDepth":364,"depth":364,"links":365},2,[366,367,376,377],{"id":46,"depth":364,"text":47},{"id":56,"depth":364,"text":57,"children":368},[369,371,372,373,374,375],{"id":65,"depth":370,"text":66},3,{"id":100,"depth":370,"text":101},{"id":116,"depth":370,"text":117},{"id":132,"depth":370,"text":133},{"id":157,"depth":370,"text":158},{"id":173,"depth":370,"text":174},{"id":223,"depth":364,"text":224},{"id":255,"depth":364,"text":256},"how-to","2026-01-13","2026-02-02","Step-by-step guide to securing Firebase with authentication-based security rules. Protect your Firestore and Realtime Database from unauthorized access.",false,"md",null,"yellow",{},true,"Step-by-step guide to Firebase security rules with authentication.","/blog/how-to/firebase-auth-rules","[object Object]","HowTo",{"title":5,"description":381},{"loc":389},"blog/how-to/firebase-auth-rules",[],"summary_large_image","BhKcraz8MF1QCrRftQhWvkBzaTdDV6Qi1PlrimED_0A",1775843928400]