1

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("test@gmail.com", "password")
db = firebase.database()
db.child("users").child(user["localId"]).set({"name": "test", "email": "test@gmail.com"}, token=user["localId"])
Jacob
  • 388
  • 2
  • 7
  • Is your `db` object a Purebase instance? If so, are you sure it is signed in with the same user as `self.user["localId"]`, or with a service account? – Frank van Puffelen Apr 13 '23 at 18:01
  • Hmm... I'm also wondering: can you try using `update` instead of `set`? – Frank van Puffelen Apr 13 '23 at 18:01
  • The db object comes from `pyrebase.initialize_app(config).db()`. I have tried to explicitly passing the users token to both a `set` and `update` request but it still didn't work. – Jacob Apr 13 '23 at 18:05
  • Did you initialize Pyrebase with a service account as shown in the second code snippet here: https://github.com/thisbejim/Pyrebase#add-pyrebase-to-your-application? It's probably better to edit your question to show a [complete-yet-minimal Python/Pyrebase script with which we can reproduce the problem](http://stackoverflow.com/help/mcve). – Frank van Puffelen Apr 13 '23 at 18:11

2 Answers2

1

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": "test@gmail.com"}, user["idToken"])
samthecodingman
  • 23,122
  • 4
  • 30
  • 54
0

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.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • I tried using these rules, but it gives the same permission denied error, but the rules playground simulation works. – Jacob Apr 13 '23 at 18:08