fodma1
fodma1

Reputation: 3535

Creating secure REST-like API with firestore

I'd like to store one-to-many relationship in firebase firestore. Let's say I have an author, and there are books belonging to this author. I could store it in a nested relationship:

author/
  authorId1 : {
    books: [{...}, {...}]
  }

But I also need a way to list all books, preferably without iterating through every author (afaik with the real-time DB it was required), so I suppose I should do

author/
  authorId1 : {
    books: [bookId1, bookId2]
  }
books/
  bookId1: {...}
  bookId2: {...}

But for security and performance reasons I'd rather not filter on the frontend. I found that it is possible to write queries:

const bookRef = fireStore.collection('books');
debtorsRef.where('author', '==', authorId).then(...);

This hopefully eliminates the performance concerns, but it not secure since it'd be possible to fetch other author's books from the client. Plus I'd rather store the relationship on the author document, not the other way around.

On a restful API for example with Django Rest Framework, I'd restrict the query set to return only books that belong to the given user. IIUC it is possible with IAM but based on the examples I'm not quite sure how.

So again, I'd like to return the book only if its id is listed in the author's books property. One book could belong to multiple authors in theory.

I guess this is a duplicate and many people had this concern, but I could not find a clear answer to this specific use case.

Upvotes: 1

Views: 759

Answers (1)

Mike McDonald
Mike McDonald

Reputation: 15953

You can write Security Rules to properly secure your query:

service cloud.firestore {
  match /databases/{database}/documents {
    match /books/{bookId} {
      allow read: if request.resource.data.author == resource.data.author
    }
  }
}

Note that at present we only support constraints on equalities (==) and not inequalities (!=, <, <=, etc.)

You can extend this concept to maintain a list of owners in a subcollection of each book, and do an existence check (using the exists() function):

service cloud.firestore {
  match /databases/{database}/documents {
    match /books/{bookId} {
      allow read: if exists(/databases/$(database)/documents/books/$(bookId)/owners/$(request.auth.uid))
      match /owners/{ownerId} {
        // Include other conditions that provide for ownership checks
        allow write: if request.auth.uid == ownerId;
      }
    }
  }
}

Upvotes: 2

Related Questions