Firebase firestore get user document without authenticated

Viewed 339

I was trying to build an application in flutter with firebase. I don't want to User to authenticate him/her to firebase authentication.

All I want them to use their phone number as a secret code. Meaning he/she can enter the phone number to view their data without authentication. Without phone number, they cannot read the data.(without OTP too).

Now I have this in firestore rule, so anybody holds the phone number can view the data.

 function isUserRef(field) { 
  return field in resource.data
    && resource.data.mobile == /customers/document/$(request.resource.data.mobile)
}

match /customers/{document=**} {
  allow read : if isUserRef(request.resource.data.mobile);
}

request resource data contain as below.

User{
"id" : null,
"mobile" : "7878445778"
}

But the above rule still doesn't match the document based on his/her mobile number. I don't want to user to authenticate at all. It's simple application were data is not a concern.

Any help appreciated!!. Thanks.

2 Answers

It's not clear how your database is set up or how you're passing the phone number, but here's a simpler approach that may help guide you.

Set your database up where the phone number is the customer's ID. If that's not possible, create a phoneToCustomers collection that is used to match phone numbers to customers.

Example 1: Phone Numbers as Customer IDs

Let's assume your customer IDs are their phone numbers:

{
  "customers": {
    "7878445778": {...},
    "1231231234": {...}
  }
}

With this simple rule you can accomplish what you want:

match /customers/{phone} {

  // Allow anyone with the phone number to access this document
  allow get: if true;

  // Can't list all customers
  allow list: if false;
}

Example 2: Customer ID Lookup Table

Let's assume your database looks like this:

{
  "customers": {
    "abc123": {...},
    "xyz987": {...}
  },
  "phoneToCustomers": {
    "7878445778": "abc123",
    "1231231234": "xyz987"
  }
}

These rules prevent users from querying your customers or phone numbers but allows retrieving documents if the user knows the ID.

match /customers/{customerId} {

  // Allow anyone with the customer ID to access this document
  allow get: if true;

  // Can't list all customers
  allow list: if false;
}

match /phoneToCustomers/{phone} {

  // Allow anyone with the phone number to access this document
  allow get: if true;

  // Can't list all customers
  allow list: if false;
}

You would then need to get() /phoneToCustomers/7878445778 to get the customer ID then a second get() to retrieve the customer data at /customers/<customerId>.

To evaluate incoming requests against other documents in the database you can use get() or exists() request, they expect fully specified document path.

Keep in mind, that functions have access to variables, that are defined in the scope where you define them.

This function checks if document named as users phone number exists:

function isUser(request) { 
  let requestData = request.resource.data.mobile;
  let docExists = exists(/databases/$(database)/documents/customers/$(requestData)); 
return docExists;

This function checks if document has field with users phone number:

function isUser(document, request) {
  let requestData = request.resource.data.mobile;
  let fieldExists = get(/databases/$(database)/documents/customers/$(document)).data.mobile == requestData;
return fieldExists;

This usecase as you can see also requires document wildcard to be passed to function.

With first function your security rules will be:

match /customers/{document} {
  allow read : if isUser(request);
}

With second function your security rules will be:

match /customers/{document} {
  allow read : if isUser(document, request);
}
Related