Firebase Learn Cloud Firestore Security Rules
Tags: firebase, javascript, programming
Published: 2021-10-04 13:46:35

I have been asked by a lot of developers this one question…

**Is Firebase safe** as the config code is exposed to the browser? 🔥

My answer is **Yes** and **No**.

The config code that Firebase provides is meant to be public.

But…

The real security lays in the [Security Rules](https://firebase.google.com/docs/rules/basics). 👮‍♂️

Having the right security rule in place, you can [build a secure web app](https://softauthor.com/vue-firestore-crud-app-authentication/) with the Cloud Firestore without needing your own server at all.

However, if you have your own server or are using cloud functions using Firebase Admin SDK, all security rules will be bypassed.

In that case, you will have to handle security manually in your server-side environment.

Let’s take a look at the SIX common scenarios that you may run into when writing Firestore Security Rules.

>*Recommended*
>[*Learn Firebase Storage Quickly - Guide*](https://softauthor.com/learn-firebase-cloud-storage-quickly-guide/)

###01. Read Permission For Anyone

Let’s say you have a posts collection and you want to show all documents from it to anyone who visits your site. You can do something like this:

```JavaScript
service cloud.firestore {    
  match /databases/{database}/documents {      
    match /posts/{docId} {        
      allow read;     
    }    
  }  
} 
```
Pretty straight forward!

The **allow:read** gives permission to read all documents in a given path, in this case, **/posts/{docId}**.

Other operations such as create, update and delete can be a different statement or merged with the read statement depending upon what type of rule you’re trying to write.

But, NEVER use **allow:write** without additional rules in place.

###02. For Authenticated Users Only

Instead of showing the posts to anyone, how about showing them to *only* authenticated users.

```JavaScript
service cloud.firestore {   
  match /databases/{database}/documents {     
    match /posts/{docId} {      
      allow read: if request.auth.uid != null     
    }   
  }
}
```

You can easily do that by checking to see if the signed-in user’s uid exists or not. The **request.auth** object has information about the signed-in user. So, you can access uid using **request.auth.uid** property.

Nice!

The third security rule will enforce that only logged-in users can read or write their own documents, not others and vice-versa.

###03. Secure Logged-In User Data

If you’re from an SQL background, this is a one-to-one relationship. One document per user in a users collection.

```JavaScript
service cloud.firestore {    
  match /databases/{database}/documents {      
    match /users/{uid} {        
      allow read, write: if request.auth.uid == uid      
    }    
  }  
} 
```

In the inner match path, you can see the users collection slash the wildcard variable **{uid}** that basically represents any document that’s inside that collection.

Using this security rule, users can only update their own document if their logged-in user ID is equal to the **uid** that already exists in the database.

On top of that, you could add an email verification check as a second condition using **request.auth.token.email_verified** flag.

```JavaScript
service cloud.firestore {    
  match /databases/{database}/documents {      
    match /users/{uid}/ {        
      allow read, write: 
        if request.auth.uid == uid &&
           request.auth.token.email_verified == true     
    }    
  }  
} 
```

###04. Never Trust The Client And Validate Data

Let’s say you have a post collection and each document inside it has a title, content, author, author_id, etc. The author_id would be an actual user ID.

![Alt text of image](https://softauthor.com/wp-content/uploads/2019/08/posts-collections-sample.png)

>*I often find that it’s easier to understand when showing the data structure before showing the security rule.*

Sometimes, you will want to validate the incoming request data before saving into the database using the **request** object.

Let’s add a security rule to validate data before allowing users to add new posts to the Cloud Firestore.

```JavaScript
service cloud.firestore {   
  match /databases/{database}/documents {     
    match /posts/{docId} {      
      allow create: 
        if request.resource.data.title is string && 
           request.data.title.size() > 5 &&
           request.data.title.size() < 500 &&
           request.resource.data.author_id == request.auth.uid     
     }   
  } 
}
```

It’s checking to see if the title is a string and also validating if the length of the title characters is between 5 and 500 long.

>*As you can see, you can add validation pretty much to all of the fields, in fact, it’s recommended because it gives more schema to your data model.*

Finally, check to see if the request.resource.data.author_id is equal to the currently logged-in user’s uid.

This is very similar to server-side validation without managing your own server. 🙂

The Firestore query for adding a new post should be something like this:

```JavaScript
firebase
  .firestore()     
  .collection("posts")     
  .add({         
      title: "JavaScript MVC",
      content: "In this JavaScript MVC...",     
      author: firebase.auth().currentUser.displayName, 
      author_id: firebase.auth().currentUser.uid     
   });
```

Check out my other article [Learn Firestore CRUD Queries Quickly](https://softauthor.com/firestore-querying-filtering-data-for-web/) if you want to know more about queries.

###05. Get Multiple Documents Owned By A Single User

Getting multiple documents by a single user often referred to a one-to-many relationship.

Before creating a rule, make sure that each document has a file called **author_id** which is basically the userId of whoever created that post.

[Continue Reading...](https://softauthor.com/firebase-cloud-firestore-security-rules/)