How to implement follow feature in firebase firestore? - firebase

I'm trying to implement Follow/Unfollow option for my users similar to Twitter. I'm thinking along the lines of below architecture for a collection named follow_map
userA
-- following : [userC, userD ...]
-- followedBy : [userC]
userC
-- following : [userA]
-- followedBy : [userA, userB ....]
I'll be using usernames instead of direct IDs maybe. Is there a better way to implement Follow/Unfollow option with firestore? If yes, plz let me know
Also I just thought of this and I'm new to Firebase so I'm not sure if I'll implement the optimal firestore rules so if possible plz let me know how to implement firestore rules for this architecture
For example I'm not sure how to allow only userA to modify only his username in the followedBy of userC.
or is it better to go about with kind of architecture mentioned here Making a follow system with firestore and cloud functions

Related

Sending extra (authentication) data with firestore request

Similar questions (eg. this) have already been asked and answered in negative. I'd like to if any alternatives exist.
I am developing an application where users can collaboratively edit a document. I don't want to force every user to login. I would like to allow users with a link to be able to edit a document (similar to what Google Docs allows). I was planning to share a token in the link which when presented would grant write access. I would have stored the tokens in a separate collection and matched them. But as per previous answers this is not possible and a security issue.
I don't consider it a security concern (for my purposes). The token is like a pre-shared key. Whoever presents the key is allowed access. If the owner thinks that the key is compromised, he can revoke the same. Kindly help me with a way to achieve this. I'm also curious to know how other apps like Google docs achieve this.
As Mentioned by #Dharmaraj,
In Firebase security rules, you have 3 pieces of information, namely the path, the data and the token. Except from those three you can't pass additional information in a security rule.
Cloud Functions would be a better fit here, given the flexibility. Additionally, with Cloud Functions you'd not be forced to authenticate users, and still be able to connect to Firestore if needed.

How to check if firebase security is well configured to avoid data stealing?

How can I make sure my firebase realtime database data is not accessible (read or download) via REST or any other way ?
I am very concerned about this as it seem to be a common way (not to secure properly your database) to steal data from apps.
My nodes all have the same security for reading : authentification required.
Thank you !
It sounds like you've left the default security rules, which simply require a user to be signed in to be able to read/write all data. While this blocking of unauthenticated users is a good first step, there is probably more you can do.
The Firebase documentation explain how you can use Firebase's server-side security rules to precisely control what data each user can access. I highly recommend also watching the video in there, for a good introduction of what mindset to have while thinking of securing your data in this way.
Ok so I found the exact answer I was looking for : if you want to download data that needs authentification with REST, you need a token.
So to sum up : No, 'simple' users can not download nodes that are protected by security rules, they also need a token that only the admin can generate.
Please feel free to correct me if all the above is wrong

Firestore - security rules for users within companies

Our current Firestore structure is as follows:
Currently we are not using any subcollections
Users have list of companies to which they belong
Every project is connected only with 1 company
Project belongs to a company, when in companyId field is written that company UID
My 1st question is how we can specify security rules defined by this database? Is there some best practice approach?
Our first idea was to do this:
match /databases/{database}/documents/projects/{projectUid}/{document=**} {
allow read: if
(/databases/$(database)/documents/projects/$(projectUid)/companyId) ===
(/databases/$(database)/documents/users/$(request.auth.uid)/companyId)
}
But according to the documentation this would mean that we would have for each read basically 3 reads (2 queries for security and 1 real read from DB). This seems like a waste of queries.
Is there a better approach than this?
We were thinking about changing to subcollections:
at the end we would have in root collections 'companies' and 'users' (to store all users details)
projects would be subcollection of companies
pages would be subcollection of projects
...etc
and companies would contain list of users (not the other way around like now) - but only list, not user details
This way we can use similar approach as from the doc, where each match would contain {companyId} and in allow statement we would use something like
match /databases/{database}/documents/companies/{companyId}/projects/{projectId} {
allow read: if
exists(/databases/$(database)/documents/companies/$(companyId)/users/$(request.auth.uid));
}
Thanks for any recommendations on how to build it in the most scalable and especially most secure way.
Have you considered adding a user's company ID as a custom claim to their profile? That way no additional reads are needed in your security rules.
Since setting these claims requires the Admin SDK, it will require that you can run trusted code somewhere. But if you don't have your own trusted environment yet, you could use Cloud Functions for that e.g. based on some other action like writes to your current Firestore structure.
Adding an answer to Frank.
Borrowing from other API SDKs such as microsoft graph, typically to make a resource request you start by initializing a Client object with an authentication token representing the scope/rights of the user. For example:
const client = new SDKClient(my_auth_token);
The client constructor would have a token validation step on claims. You can then make REST calls such as
const response = await client.someEndpoint({ method: 'POST', body: my_object });
I suggest rather than using the admin SDK for read/write to your firestore, you use the regular firebase nodejs client. To restrict access with security rules, pass a firebase JWT token into this custom SDKClient class with the token that you obtain from the header of your requests. In the constructor, initialize a new firebase 'app'. Because a regular firebase client is
subject to security rules, this will do what you're looking for.
Some example code has already been offered in this answer.
I should add that according to this firebase doc there is a 'warning' to use the admin-sdk server-side, but I'm not sure I see why.
One approach I've thought of for something similar that we are working on, that is, private chatrooms where only certain users have access, is to encrypt all messages with an on-server key, and only grant read access for that key to certain users. That way the extra read only has to occur one time, just when getting the key for the first time, then normal reads with no additional security rules are fine, as an attacker wouldn't be able to do anything with them since they are encrypted and they don't have access to the key.

How to work around a lack of an `IN` clause in Firebase Query with a query for 500 filters

I need to create a typical find friends feature in my mobile app that's using Firebase. The user would upload a list of hashed contact emails or phone numbers from their address book and the server would return a list of usernames that are already using the application. The typical user would have around 500 contacts in their address book.
This would be pretty straightforward to set up using a traditional SQL or Mongo database but in Firebase this would be difficult because I don't see any WHERE IN clauses with Firebase Query and it seems like it would be very inefficient using a Firebase Database for this. Even if I created a specific HashedPhoneNumbers collection with the hash being the id, it still seems like a monster query. Is there a way to make this query run efficiently in Firebase?
i.e. SELECT username from Users WHERE phoneHash IN [list of 500 phone hashes]
Alternatively, if I were to use Google Cloud DataStore looks like it supports chaining a bunch of AND email_hash = XXX filters together, but I don't know how efficient that would be if the filter list is 500 filters chained together.
Yes it does. For that i recomand you to see: The Firebase Database For SQL Developers and NoSQL Data Modeling Techniques.
It's it does not support this kind of query but there method with which you can achieve the same thing. Explained in the above tutorial.
Yes it does. For this i recomand you to use Cloud Storage For Firebase.
As a conclusion, i kindly recomand you using Firebase.

Do I need security rules on my Firebase Database?

It is unclear whether or not to set security rules for database.
Is it enough to just let in just authenticated users? Do I need more complicated things? I have android app, and do all validations and updates inside app.
The video from IO says that there is possibility that someone can get all your data if he knew your app ID. So if user is authenticated and have app ID and somehow build web app he can get data too? I mean if using simple rules.
I`m asking for risks when building just android app and using simple rules (auth is on).
Is it ok for you if any user could edit/create/delete any data in your Firebase database? If this is not ok, you need security rules (you probably need them)
Firebase's security rules are really powerful and easy to use, I suggest you take a look at the documentation.
You need user id or role specific rules, otherwise somebody for example can easily wipe out your all data, or easily manipulate anything.

Resources