Basic Security Rules

Firebase Security Rules allow you to control access to your stored data. The flexible rules syntax means you can create rules that match anything, from all writes to the entire database to operations on a specific document.

This guide describes some of the more basic use cases you might want to implement as you set up your app and safeguard your data. However, before you start writing rules, you might want to learn more about the language they're written in and their behavior.

To access and update your rules, follow the steps outlined in Manage and deploy Firebase Security Rules.

Default rules: Locked mode

When you create a database or storage instance in the Firebase console, you choose whether your Firebase Security Rules restrict access to your data (Locked mode) or allow anyone access (Test mode). In Cloud Firestore and Realtime Database, the default rules for Locked mode deny access to all users. In Cloud Storage, only authenticated users can access the storage buckets.

Cloud Firestore

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
  }
}

Realtime Database

{
  "rules": {
    ".read": false,
    ".write": false
  }
}

Cloud Storage

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if request.auth != null;
    }
  }
}

Development-environment rules

While you're working on your app, you might want relatively open or unfettered access to your data. Just be sure to update your Rules before you deploy your app to production. Also remember that if you deploy your app, it's publicly accessible — even if you haven't launched it.

Remember that Firebase allows clients direct access to your data, and Firebase Security Rules are the only safeguard blocking access for malicious users. Defining rules separately from product logic has a number of advantages: clients aren't responsible for enforcing security, buggy implementations will not compromise your data, and most importantly, you're not relying on an intermediary server to protect data from the world.

All authenticated users

While we don't recommend leaving your data accessible to any user that's signed in, it might be useful to set access to any authenticated user while you're developing your app.

Cloud Firestore

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.auth != null;
    }
  }
}

Realtime Database

{
  "rules": {
    ".read": "auth.uid !== null",
    ".write": "auth.uid !== null"
  }
}

Cloud Storage

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if request.auth != null;
    }
  }
}

Production-ready rules

As you prepare to deploy your app, make sure your data is protected and that access is properly granted to your users. Leverage Authentication to set up user-based access and read directly from your database to set up data-based access.

Consider writing rules as you structure your data, since the way you set up your rules impacts how you restrict access to data at different paths.

Content-owner only access

These rules restrict access to the authenticated owner of the content only. The data is only readable and writable by one user, and the data path contains the user's ID.

When this rule works: This rule works well if data is siloed by user — if the only user that needs to access the data is the same user that created the data.

When this rule doesn't work: This ruleset doesn't work when multiple users need to write or read the same data — users will overwrite data or be unable to access data they've created.

To set up this rule: Create a rule that confirms the user requesting access to read or write data is the user that owns that data.

Cloud Firestore

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow only authenticated content owners access
    match /some_collection/{userId}/{documents=**} {
      allow read, write: if request.auth != null && request.auth.uid == userId
    }
  }
}

Realtime Database

{
  "rules": {
    "some_path": {
      "$uid": {
        // Allow only authenticated content owners access to their data
        ".read": "auth !== null && auth.uid === $uid",
        ".write": "auth !== null && auth.uid === $uid"
      }
    }
  }
}

Cloud Storage

// Grants a user access to a node matching their user ID
service firebase.storage {
  match /b/{bucket}/o {
    // Files look like: "user/<UID>/path/to/file.txt"
    match /user/{userId}/{allPaths=**} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
    }
  }
}

Mixed public and private access

This rule allows anyone to read a data set, but restricts the ability to create or modify data at a given path to the authenticated content owner only.

When this rule works: This rule works well for apps that require publicly readable elements, but need to restrict edit access to those elements' owners. For example, a chat app or blog.

When this rule doesn't work: Like the content-owner only rule, this ruleset doesn't work when multiple users need to edit the same data. Users will ultimately overwrite each other's data.

To set up this rule: Create a rule that enables read access for all users (or all authenticated users), and confirms the user writing data is the owner.

Cloud Firestore

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow public read access, but only content owners can write
    match /some_collection/{document} {
      // Allow public reads
      allow read: if true
      // Allow creation if the current user owns the new document
      allow create: if request.auth.uid == request.resource.data.author_uid;
      // Allow updates by the owner, and prevent change of ownership
      allow update: if request.auth.uid == request.resource.data.author_uid
                    && request.auth.uid == resource.data.author_uid;
      // Allow deletion if the current user owns the existing document
      allow delete: if request.auth.uid == resource.data.author_uid;
    }
  }
}

Realtime Database

{
// Allow anyone to read data, but only authenticated content owners can
// make changes to their data

  "rules": {
    "some_path": {
      "$uid": {
        ".read": true,
        // or ".read": "auth.uid !== null" for only authenticated users
        ".write": "auth.uid === $uid"
      }
    }
  }
}

Cloud Storage

service firebase.storage {
  match /b/{bucket}/o {
    // Files look like: "user/<UID>/path/to/file.txt"
    match /user/{userId}/{allPaths=**} {
      allow read;
      allow write: if request.auth.uid == userId;
    }
  }
}

Attribute-based and Role-based access

For these rule to work, you must define and assign attributes to users in your data. Firebase Security Rules check the request against the data from your database or file's metadata to confirm or deny access.

When this rule works: If you're assigning a role to users, this rule makes it easy to limit access based on roles or specific groups of users. For example, if you were storing grades, you could assign different access levels to the "students" group (read their content only), the "teachers" group (read and write in their subject), and the "principals" group (read all content).

When this rule doesn't work: In Realtime Database and Cloud Storage, your rules can't leverage the get() method that Cloud Firestore rules can incorporate. Consequently, you have to structure your database or file metadata to reflect the attributes you're using in your rules.

To set up this rule: In Cloud Firestore, include a field in your users' documents that you can read, then structure your rule to read that field and conditionally grant access. In Realtime Database, create a data path that defines your app's users and grants them a role in a child node.

You can also set up custom claims in Authentication and then retrieve that information from the auth.token variable in any Firebase Security Rules.

Data-defined attributes and roles

These rules only work in Cloud Firestore and Realtime Database.

Cloud Firestore

Remember that any time your rules include a read, like the rules below, you're billed for a read operation in Cloud Firestore.

service cloud.firestore {
  match /databases/{database}/documents {
    // For attribute-based access control, Check a boolean `admin` attribute
    allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true;
    allow read: true;

    // Alterntatively, for role-based access, assign specific roles to users
    match /some_collection/{document} {
     allow read: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "Reader"
     allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "Writer"
   }
  }
}

Realtime Database

{
  "rules": {
    "some_path": {
      "${subpath}": {
        //
        ".write": "root.child('users').child(auth.uid).child('role').val() === 'admin'",
        ".read": true
      }
    }
  }
}

Custom-claim attributes and roles

To implement these rules, set up custom claims in Firebase Authentication and then leverage the claims in your rules.

Cloud Firestore

service cloud.firestore {
  match /databases/{database}/documents {
    // For attribute-based access control, check for an admin claim
    allow write: if request.auth.token.admin == true;
    allow read: true;

    // Alterntatively, for role-based access, assign specific roles to users
    match /some_collection/{document} {
     allow read: if request.auth.token.reader == "true";
     allow write: if request.auth.token.writer == "true";
   }
  }
}

Realtime Database

{
  "rules": {
    "some_path": {
      "$uid": {
        // Create a custom claim for each role or group
        // you want to leverage
        ".write": "auth.uid !== null && auth.token.writer === true",
        ".read": "auth.uid !== null && auth.token.reader === true"
      }
    }
  }
}

Cloud Storage

service firebase.storage {
  // Allow reads if the group ID in your token matches the file metadata's `owner` property
  // Allow writes if the group ID is in the user's custom token
  match /files/{groupId}/{fileName} {
    allow read: if resource.metadata.owner == request.auth.token.groupId;
    allow write: if request.auth.token.groupId == groupId;
  }
}

Tenancy attributes

To implement these rules, set up multitenancy in Google Cloud Identity Platform (GCIP) and then leverage the tenant in your rules. The following examples allow writes from a user in a specific tenant e.g. tenant2-m6tyz

Cloud Firestore

service cloud.firestore {
  match /databases/{database}/documents {
    // For tenant-based access control, check for a tenantID
    allow write: if request.auth.token.firebase.tenant == 'tenant2-m6tyz';
    allow read: true;
  }
}

Realtime Database

{
  "rules": {
    "some_path": {
      "$uid": {
        // Only allow reads and writes if user belongs to a specific tenant
        ".write": "auth.uid !== null && auth.token.firebase.tenant === 'tenant2-m6tyz'",
        ".read": "auth.uid !== null
      }
    }
  }
}

Cloud Storage

service firebase.storage {
  // Only allow reads and writes if user belongs to a specific tenant
  match /files/{tenantId}/{fileName} {
    allow read: if request.auth != null;
    allow write: if request.auth.token.firebase.tenant == tenantId;
  }
}