How to create public/private user profile with Firebase security rules?
{
"rules": {
"users": {
"$uid":{
//Private whatever under "uid" but Public is exposed
".read": "auth != null && auth.uid == $uid",
".write": "auth != null && auth.uid == $uid",
"public": { ".read": "auth != null" }
}
}
}
}
- I've created these rules to have users public/private profile
- "users/{uid}/public" profile should be accessible by any users those are authenticated, but cannot access the data under "users/uid"
Here is some fake data that is stored in my firebase database.
{
"users" : {
"YFIIAgwa2kaannrXjwvSZmoywma2" : {
"Name:" : "Example 1",
//This public child should be accessible by
//"Example 2" but cannot know the name of
// this user
"public" : {
"email" : "[email protected]"
}
},
"YgSfSzPzxLbyDL17r6P9id2cdvH2" : {
"Name:" : "Example 2",
//This public child should be accessible by
//"Example 1" but cannot know the name of
// this user
"public" : {
"email" : "[email protected]"
}
}
}
}
I want to know if this is the robust way to prevent any users from accessing user's critical information! Is there anyway I can improve this by using validate? I am open to any suggestions you guys have. I want to create the best and simple security rules for my app.
Solution 1:
You can definitely secure access to the private and public data with your current data structure.
But one use-case you'll likely want at some point is to show a list of the public info for all users. With your current data structure that is not possible, because Firebase's security model cannot be used to filter data. For a great answer covering this, see Restricting child/field access with security rules.
Most developers split the public and private data in completely separate subtrees:
{
"users" : {
"YFIIAgwa2kaannrXjwvSZmoywma2" : {
"Name:" : "Example 1",
},
"YgSfSzPzxLbyDL17r6P9id2cdvH2" : {
"Name:" : "Example 2",
}
},
"public_profiles": {
"YFIIAgwa2kaannrXjwvSZmoywma2" : {
"email" : "[email protected]"
},
"YgSfSzPzxLbyDL17r6P9id2cdvH2" : {
"email" : "[email protected]"
}
}
}
You can then secure access with:
{
"rules": {
"users": {
"$uid":{
".read": "auth != null && auth.uid == $uid",
".write": "auth != null && auth.uid == $uid",
}
},
"public_profiles": {
".read": "auth != null",
"$uid":{
".write": "auth != null && auth.uid == $uid",
}
}
}
}
Now any authenticated user can listen to /public_profiles
, which means you can easily show a list of these profiles.
Solution 2:
Hmm wouldn't it be easier to (re)structure the db so that you have a public and a private field per user? Something like:
{
"users" : {
"YFIIAgwa2kaannrXjwvSZmoywma2" : {
"private": {
"Name:" : "Example 1"
},
"public" : {
"email" : "[email protected]"
}
},
"YgSfSzPzxLbyDL17r6P9id2cdvH2" : {
"private": {
"Name:" : "Example 2"
},
"public" : {
"email" : "[email protected]"
}
}
}
}
/UPD: This way it should be easy(er) to have the different permissions because they won't inherit them from the parent?