mercredi 26 octobre 2022

When/where is the best moment to check for Firestore document ownership (service or middleware)

When implementing security rules to ensure a user can only fetch/update their own documents in Firestore, where should I put the logic?

(Before you say 'in Firestore Security Rules file', please note that I am using the Firebase Admin SDK which bypasses these security rules rather than the frontend Firebase SDK.)

For more context:

  • I have built a CRUD REST API using a Koa server implemented in Firebase Cloud Functions which documents stored in Firestore.
  • API calls are authenticated using Firebase Auth, and I decode the authorization token to get the User ID of the person calling it.
  • I created a FirestoreService class which can fetch and read data from Firestore.
  • I use custom Koa middleware to check the user has relevant roles and permissions (uses AccessControl library) but this middleware doesn't check for document ownership, only that someone has the permission to 'getOwn' or 'getAny'.

But where should I put the logic to check, for example, that a document being fetched has a 'userId' property set to the ID of the currently logged in user.

It seems I have 3 options:

  1. In middleware. Before passing responsibly to controller to do the work, middleware should perform a 'get' operation then check the userId attribute of the document returned matches the logged in user. Downsides of this approach is that I am fetching the document twice - once to check permissions and then again in the controller.

  2. In controller. Once the data has been fetched from the database I do the userId check. Downsides of this are code replication as I'll have to write this logic in each controller function.

  3. In service. Perform the check in the FirestoreService class once the data has been fetched. Downside of this approach is that it feels like I'm adding additional logic to a service which should remain generic. The service get method would need to be called with details about what attributes to check and know the userId.

What's the best approach to this puzzle in terms of architecture?

Bear in mind it should work for all CRUD operations, not just the 'read' operation.

Any help much appreciated!

I started with the logic in the service but it feels clunky.

Aucun commentaire:

Enregistrer un commentaire