background-shape

Namaskaram,

Many applications require Role Based access. For example : in an e-commerce project, roles like Admin, Shopkeeper, Agent etc. may exist. Granting and revoking the access manually can be hard & inefficient.

In this blog, I am sharing an easy & efficient way to grant & revoke role based access in a Firebase app.

Naive approach

  • Let’s say : you have an Admin app where only authorised Admins should be able to login & access the app.

  • So you can have an admins collection with documents of authorised admin in Firestore

  • When access is to be revoked from Admin, then respective admin document can be deleted

  • To keep track of whether admin has access or not, we can read the respective admin document every single time admin opens the app

  • If the document is found, then admin still has access and if the document doesn’t exist then admin access is revoked.

The problem with this approach is : we have to read the Admin document each time the app is opened. Suppose we need to show noOfShops to the Admin in MainActivity. Then we need to read at least 2 documents :

  1. Admin doc to check permission

  2. noOfShops

We can reduce this 2 documents read to only 1. Just by reading noOfShops, you can know Admin permission also. Here is how!

Efficient approach using security rules

Firestore provides an amazing feature of security rules. By defining these security rules, you can save time & bandwidth. Without talking much let me show you the rule directly :

Firebase Security Rule

So here we have defined a method isAdmin() which checks whether the respective Admin document exists or not. And the rule ensures that read-write is allowed only when the respective Admin’s document exists.

Note

  • You need not define this rule for the entire database. If you want, you can define it only for a particular collection or document.

  • This security rule ensures that only authenticated (logged in) users can access data (auth.uid != null). This is known as Firestore Locked mode. Learn more about this in this video.

  • Learn more about writing security rules here.

Catching the exception

While making the request to read noOfShops from the app, an exception may occur when our security rule fails i.e. if the Admin document doesn’t exist. We need to handle this exception in our app and when this exception occurs it is clear that Admin access has been revoked.

This exception is StorageException and you can handle it like this :

public void fetch(){
        FirebaseFirestore.getInstance()
                .document("stats/noOfShops")
                .get()
                .addOnSuccessListener(documentSnapshot -> {
                    //TODO
                })
                .addOnFailureListener(e -> {
                    if(((FirebaseFirestoreException) e).getCode().value() == 7){
                        //Access Revoked
                    }
                });
    }

Login

When a user attempts to log in as an Admin, we can read the Admin document. If it exists, then admin has access else not. But for the next time, when the admin opens the app, we just need to query for the data we need. It will automatically fail if the admin access is revoked.

Conclusion

In this way, by leveraging the security rules we can save time and bandwidth instead of reading a document each time the app opens. StorageException failure in querying the data we need implies that the security rule declined the request. By catching this exception we can revoke the access.