Secure User Data

Firebase Storage Security Rules integrates with Firebase Authentication to provide powerful user based authentication to Firebase Storage. This allows for granular access control based on claims of a Firebase Authentication token.

User authentication

When an authenticated user performs a request against Firebase Storage, the request.auth variable is populated with the user's uid (request.auth.uid) as well as the claims of the Firebase Authentication JWT (request.auth.token).

Additionally, when using custom authentication, additional claims are surfaced in the request.auth.token field.

When an unauthenticated user performs a request, the request.auth variable is null.

Using this data, there are several common ways to use authentication to secure files:

  • Public: ignore request.auth
  • Authenticated private: check that request.auth is not null
  • User private: check that request.auth.uid equals a path uid
  • Group private: check the custom token's claims to match a chosen claim, or read the file metadata to see if a metadata field exists

Public

Any rule that doesn't consider the request.auth context can be considered a public rule, since it doesn't consider the authentication context of the user. These rules can be useful for surfacing public data such as game assets, sound files, or other static content.

// Anyone to read a public image if the file is less than 100kB
// Anyone can upload a public file ending in '.txt'
match /public/{imageId} {
  allow read: if resource.size < 100 * 1024;
  allow write: if imageId.matches(".*\.txt");
}

Authenticated private

In certain cases, you may want data to be viewable by all authenticated users of your application, but not by unauthenticated users. Since the request.auth variable is null for all unauthenticated users, all you have to do is check the request.auth variable exists in order to require authentication:

// Require authentication on all internal image reads
match /internal/{imageId} {
  allow read: if request.auth != null;
}

User private

By far the most common use case for request.auth will be to provide individual users with granular permissions on their files: from uploading profile pictures to reading private documents.

Since files in Firebase Storage have a full path to the file, all it takes to make a file controlled by a user is a piece of unique, user identifying information in the file path (such as the user's uid) that can be checked when the rule is evaluated:

// Only a user can upload their profile picture, but anyone can view it
match /users/{userId}/profilePicture.png {
  allow read;
  allow write: if request.auth.uid == userId;
}

Group private

Another equally common use case will be to allow group permissions on an object, such as allowing several team members to collaborate on a shared document. There are several approaches to doing this:

  • Mint a Firebase Authentication custom token that contains additional information about a group member (such as a group ID)
  • Include group information (such as a group ID or list of authorized uids) in the file metadata

Once this data is stored in the token or file metadata, it can be referenced from within a rule:

// 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;
}

Full example

Simple cases of the four common types of authentication restrictions are shown in the example below:

service firebase.storage {
  match /b/<your-firebase-storage-bucket>/o {
    match /images {
      // Anyone can view any image (no auth, publicly readable)
      match /{allImages=**} {
        allow read;
      }

      // Only authenticated users can write to "public" images
      match /public/{imageId} {
        allow write: if request.auth != null;
      }

      // Only an individual user can write to "their" images
      match /{userId}/{imageId} {
        allow write: if request.auth.uid == userId;
      }

      // Allow a "group" of users to read/write to shared images
      // An owner metadata property on the object contains the groupId for reads
      // A custom token has been minted with a groupId property for writes
      match /{groupId}/{imageId} {
        allow read: if resource.metadata.owner. == request.auth.token.groupId;
        allow write: if request.auth.token.groupId == groupId;
      }
    }
  }
}

Send feedback about...

Need help? Visit our support page.