Search code examples
javaandroidfirebasegoogle-cloud-firestorefirebase-security

Firestore Database Rules for Authenticated User Email


Objective: The document of the user who is signed in should be accessible by the user.

Collection Structure :

> root(collection_name)
    > user1@gmail.com(document_name)
        > "name" : "User One"(field key and value)
    > user2@gmail.com
        > "name" : "User TWO"

Android Code I Used

db.collection("/root/")
                .get()
                .addOnCompleteListener(task -> {
                    if (task.isSuccessful()) {
                        for (QueryDocumentSnapshot document : Objects.requireNonNull(task.getResult())) {
                            System.out.println(document.getId() + " => " + document.getData());
                        }
                    } else {
                        System.out.println(task.getException());
                    }
                });

Database Rules I tried :

    service cloud.firestore {
      match /databases/{database}/documents {
        match /root/{email} {
          allow read, update, delete: if request.auth.token['email'] == email;
          allow create: if request.auth != null;
        }
      }
    }
    

Error I Get :

com.google.firebase.firestore.FirebaseFirestoreException: PERMISSION_DENIED: Missing or insufficient permissions.

Listen for Query(target=Query(root order by name);limitType=LIMIT_TO_FIRST) failed: Status{code=PERMISSION_DENIED, description=Missing or insufficient permissions., cause=null}

I also tried using

service cloud.firestore {
  match /databases/{database}/documents {
    match /root/{email} {
      allow read, update, delete: if request.auth!=null;
      allow create: if request.auth != null;
    }
  }
}

The above rule returns me all the documents in the collection but I only want it to return the document of the specific user who is signed in. So I know that the issue is in checking the email of the user.


Solution

  • When you are using the following rules:

    match /root/{email} {
      allow read, update, delete: if request.auth.token['email'] == email;
      allow create: if request.auth != null;
    }
    

    It means that you allow only the authenticated user to read, update or delete data at the location you are pointing to, which is the user's document. However, in your code, you request data from the entire "root" collection:

    db.collection("/root/").get()
    

    Hence that error message. To solve this, you either change the query in your code, or you change the rules. But most likely you should change the way you are getting the data by using the following reference:

    db.collection("root").document(userEmail).get().addOnCompleteListener(/* ... /*);