I have a website where users can upgrade to a premium account. The page looks like this.
When they click the red subscribe button it lets the user know they have been successful. The subscriber data is then added to the subscribers collection in my database. Here is an example
This is all secured with authentication rules to prevent anyone seeing who subscribed to my website.
Problem
When I have my rules configured like below then I am unable to click the red subscribe button.
{
"rules": {
"users": {
".indexOn": "username",
".read": true,
".write": true
},
"subscribe":{
"$uid": {
".read": "auth != null && auth.token.email_verified == true",
".write": "auth !== null && auth.uid === $uid",
}
When I swap the read & write then I am able to click the red subscribe button and it all works fine.
{
"rules": {
"users": {
".indexOn": "username",
".read": true,
".write": true
},
"subscribe":{
"$uid": {
".read": "auth !== null && auth.uid === $uid",
".write": "auth != null && auth.token.email_verified == true"
}
I dont understand why subscribing doesnt work when I add the uid requirement in my rules for writing but it works when I swap them around. The database has not changed so surely both conditions should behave the same?
Possible theory
Maybe its because of the way my database is structured currently. Everything is public and there are no private vs public collections. I am not sure though. I saw this mentioned in these answer threads:
• Firebase: How to structure public/private user data
Ashok has explained about the set of rules behavior. Let me clarify further for your comment on "read" = "seeing" webpage.
{
"subscribe": {
"$uid": {
".read": "auth !== null && auth.uid === $uid",
".write": "auth != null && auth.token.email_verified == true"
}
}
}
I want to point out the $uid right below the subscribe key. This $uid means giving this position as variable to check and name it "$uid"
{
"subscribe": {
"0": {
"age": 24,
"email": "ameraz@email.com",
"name": "Alex Meraz"
},
"1": {
"age": 21,
"email": "mrafi@email.com",
"name": "Mohammed Rafi"
},
"b8eVaJs1JMVjRJQ2X3vE0PHl70B3": {
"abcabc": "aasd"
}
}
}
Now lets say my User UID is "b8eVaJs1JMVjRJQ2X3vE0PHl70B3", i can see my data only as
{
"abcabc": "aasd"
}
this is because i got
".read": "auth !== null && auth.uid === $uid"
Meaning auth from auth module not null and auth.uid equals to $uid key which is iterated matching from the array (last item key).
Now for write condition
".write": "auth != null && auth.token.email_verified == true"
Meaning allow any user that is authenticated and email verified. So $uid not used here, any verified email user can do anything with existing or non-existing key.
Previous entry just shows you the working logic (which probably has risk of accessing other people subscription), now lets dive in to the incorrect conditions.
".read": "auth != null && auth.token.email_verified == true",
This will give you access to all the items (with key 0, 1, and b8eVaJs1JMVjRJQ2X3vE0PHl70B3) if the logged in user email verified.
".write": "auth !== null && auth.uid === $uid",
This will only give write access to the already existing one (modify only to item b8eVaJs1JMVjRJQ2X3vE0PHl70B3), you can not add more item to the sibling of this key, you have access only inside this key.
Which is:
{
"abcabc": "aasd"
}