Hi, I want to raise a discussion around a topic that Iāve thought about for a while but never discussed with others using Parse.
Weāve got a fairly large application powered by Parse, ~100 classes with roughly ~300m objects in total. Weāve got a couple of clients calling this application, 2 web apps (React) and 2 native apps (React Native). A couple of years ago we realized that mutating objects on each client had a couple of issues.
If you want to mutate multiple objects from multiple classes youāre more exposed to network errors that could result in an inconsistent state.
Itās painful to maintain duplicated mutation logic between the clients (since they are all running JavaScript this could be done with a shared lib though).
Itās hard to keep track of all the different mutations that are spread among the clients.
An authenticated user could in theory corrupt their data by just making requests towards the API, which is far from ideal.
For these reasons we moved all our mutations to be encapsulated in Cloud Functions instead. Since we didnāt want the clients to be able to perform unintended mutations we have basically all our CLPs set to read only (we still perform queries in the clients).
This however causes a quite heavy use of āuseMasterKeyā for mutations. We still authenticate each cloud function based on roles and object ownership etc, but this increases the risk of unintentionally exposing objects that the calling user shouldnāt have access to. This really comes down to the fact that instead of just using the CLP we have to maintain the security for each Cloud Function which is more prone to dev errors.
A solution to this would be to basically disable all mutations that doesnāt originate from Cloud Functions so we can updated our CLPs to include write permissions which would enable us to use āsessionTokenā instead of āuseMasterKeyā.
Whatās your thoughts on this? Does it sound crazy or have to also felt the need to channel all your mutations via Cloud Functions?
I got your points and I believe your idea makes sense. Unfortunately there is no built-in function for that. But I believe that you could perhaps add an Express.js custom middleware before Parse and block requests to the classes endpoints.
Many thanks for your reply, good to hear that the reasoning is sound. If I add an Express.js middleware I would still need something to distinguish requests from Cloud Functions right? Because mutations are still routed via HTTP?
I guess directAccess might solve that, but there seem be a memory issue tied to it in the current release. On that note, do you know when the next release will happen? There seem to be many great features that have been merged but not released yet.
Yes. Youād have to use the direct access flag. Or, if perhaps you are using a reverse proxy on top of parse server, you can block the requests to the functions using it. I am not sure about the next release date but I agree if you that we already have a lot of great improvements to publish. I will discuss with the team a target date for that.
Ah, that could work I guess. Weāre using Heroku however, so weāre not really in control of the reverse proxy. We could try to check the origin IP at the application level, but then we would have to allow all IPs from AWS eu-west-1 region. The best solution is probably to wait for the direct access flag.
Iām really looking forward towards the next release. Thank you for your hard work!
Are there any updates on how to achieve this since it was originally asked? Iām also interested in allowing mutations from cloud functions only. Also regarding the directAccess flag: from what I can tell it is enabled by default, but the documentation states that it is false by default.
You could set directAccess: true and add a middleware in express that rejects traffic for relevant API paths you donāt want clients to be able to access.
If you need to allow traffic originating from your server environment, you can just check req.ip in middleware and allow those requests. To get an idea what that looks like see below.
We donāt do above in our Parse Server, but we do use a middleware for Firebase AppCheck validation on /functions. (I use /functions here and not /parse/functions, because my mountPath is / for Parse and not /parse)