skip to Main Content

My database has a users child with fields email and name, with the key being the users uid. Here are the database rules:

{
  "rules": {
     "users": {
       "$uid": { 
         "email": {
           ".read": "auth.uid == $uid",
           ".write": "auth.uid == $uid"
        },
         "name": {
           ".read": "auth.uid == $uid",
           ".write": "auth.uid == $uid"
        }
      }
    }
  }
}

I am using pyrebase to access the firebase project. Here is the statement that tries to add them to users:

db.child("users").child(self.user["localId"]).set({"name": name, "email" : email})

While creating a new user, I get a permission denied error. The user is still able to sign in though. When I make a simulated request with the rules playground, it succeeds.

edit: Here is a reproducible example:

import pyrebase

config = {
    "apiKey": "",
    "authDomain": "",
    "projectId": "",
    "databaseURL": "",
    "storageBucket": "",
    "messagingSenderId": "",
    "appId": "",
    "measurementId": "",
}
firebase = pyrebase.initialize_app(config)
user = firebase.auth().sign_in_with_email_and_password("[email protected]", "password")
db = firebase.database()
db.child("users").child(user["localId"]).set({"name": "test", "email": "[email protected]"}, token=user["localId"])

2

Answers


  1. If you want the user to be write their own name and email, but no other properties, the more idiomatic way to do that would be:

     "users": {
       "$uid": { 
         ".read": "auth.uid == $uid",
         ".write": "auth.uid == $uid"
         "email": {
           ".validate": true
         },
         "name": {
           ".validate": true
         },
         "$other": {
           ".validate": false
         }
      }
    }
    

    So we authorize writing for the entire /users/$uid node here only once, and then determine what individual child properties are valid under there, and disallow all other properties.

    Login or Signup to reply.
  2. The user ID (user["localId"]) shouldn’t be passed in as the authentication token. You need to pass the user’s ID token instead (user["idToken"]). So while you may be writing to the correct location, you are doing so without providing the right authorization.

    db.child("users").child(user["localId"]).set({"name": "test", "email": "[email protected]"}, user["idToken"])
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search