Permission denied to set value to Firebase database - ios

In my firebase database, I have set the following rule:
{
"rules": {
"Users": {
"$uid": {
".write": "$uid === auth.uid",
".read": "$uid === auth.uid"
}
}
}
}
I am developing iOS app with Firebase. I use Facebook authentication to login to my app, I would like to add user id to database when the login is successful, this is my code:
let ref = Database.database().reference()
...
// I got uid
ref.child("Users").setValue(uid)
But I got error:
setValue: or removeValue: at /users failed: permission_denied
Why?

You don't have permission to write a value to /users, so the operation is denied.
You do have permission to write a value to /users/$uid. You're probably trying to do something like this:
ref.child("Users").child(uid).setValue(true)

Related

firebase rules allow only certain user to write key valus

i want to write firebase realtime database rule where certain user can only write cetain key
ex: user with UID underlined in red can write value of key franchise_active only
user with UID underlined in green can write value of key vendor_active only
both users can read
Sounds possible. Something like this should work:
{
"rules": {
"application_status": {
"$uid1": {
"$uid2": {
"franchise_active": {
".write": "auth.uid === $uid1"
},
"vendor_active": {
".write": "auth.uid === $uid2"
}
}
}
}
}
}

How to make my Realtime database readable only by my users?

I am using the Firebase Realtime database only to know if I still have a connection to it like suggester here. So, there is nothing in it.
I thought the rules that I put was enough, but Google thinks it is not safe and I need to change it.
So, I went from:
{
"rules": {
".read": "auth != null",
".write": false
}
}
To this:
{
"rules": {
".read": false,
".write": false
}
}
That worked fine for my iOS app, but not with my Android app. Putting the 'read' to 'false' makes that solution not workable because of the solution suggested here.
What would you suggest me?
For those of you that had the same issue, here what Google tech support suggested me
You could modify this a bit like FirebaseDatabase.getInstance().getReference(“connect/” + (new Date()).toString()).keepSynced()
And in your Realtime Database rules, allow to read, write auth != null to this “connect” child.
It would look like this:
{
"rules": {
"connect":{
".read": "auth != null",
".write": "auth != null"
},
".write": false,
".read": false
}
}

Listener at /users failed: permission_denied

I have a Sign Up Flow using Firebase. When I check if an email already exists in the database, like so:
refUsers.queryOrdered(byChild: "email").queryEqual(toValue: emailText).observeSingleEvent(of: .value, with: { snapshot in
if (snapshot.value is NSNull) {
print("Unique email")
// Move to Password View.
let passwordViewController = self.storyboard?.instantiateViewController(withIdentifier: "PasswordViewController") as! PasswordViewController
self.navigationController?.present(passwordViewController, animated: true, completion: nil)
// Pass the emailText to the last View of the flow.
self.singleton.sharedInstance.emailText = emailText!
}
else {
print("Duplicate email")
}
})
The problem is, I don't have the permission to view /users in the database cause my rule is:
{
"rules": {
".read": "auth != null",
".write": "auth != null"
}
}
I know I can find if an email is a duplicate using Auth.auth().createUser but it's not just email that I'm checking in the sign up flow. I use the same method for unique username, as well. How can I achieve this?
As you can see this is not the best way to do it. You should not manually check if email already exists - Firebase can do that for you when user signs up and why would you not want to use that?
What you need is a different approach. I can think of two ways right now:
First:
You can add a new rule to Firebase, eg:
{
"rules": {
"usernames": {
".read": true,
".write": "auth != null"
},
"emails": {
".read": true,
".write": "auth != null"
}
}
}
What you do here is create a new node named usernames which every user can access and read.
Here you should hold a copy of all usernames that registered users have and when registering check if users username is already inside this node.
Second way:
You could modify your signup flow a bit and let users register without a username. After account is created you let them set a username. With a nice flow it would all look as the same registration form.
UPDATE
With rules above users should be able to read from emails and usernames without being registered. This way you can fetch data and compare if email or username is already in use.
Just make sure that when user registers you insert his email and username into those two nodes.
Though #ZassX answered helped me, I've learned what a good approach for this would be, for those who are confused like me.
The best approach is to keep users data safe in /users with "auth != null" rule. Only show the user's meta data to everyone that includes just the email and password of each user. For example:
Database
{
“metaData”: {
uid: {
“email”: …,
“password”: …
}
},
“users”: {
uid: {
“email”: …,
“password”: …
// other information
}
}
}
Security
{
"rules": {
“metaData”: {
“.read”: true,
“.write”: “auth !== null”
},
“users”: {
“.read”: “auth !== null”,
“.write”: “auth !== null”
}
}
}
The information in metaData can now be matched without a user being authenticated first. Of course, this can get more complex as you add more security but for easy understanding, this is it.

Firebase (Swift) runTransactionBlock: permission denied

May I ask what runTransactionBlock is doing behind the hood? When I run a simple setValue with the exact same rules it works, but not with runTransactionBlock. I suspect that behind the hood runTransactionBlock writes to paths outside of just the path I stated, which is causing my security rules to deny permission. Hence, I have to write a global ".write": "auth != null" and avoid doing stuff such as my wildcard ".validate": false.
My security rules are mapped out this way:
{
"rules": {
// NOTE: I NEED THIS GLOBAL WRITE ALLOW FOR TRANSACTION TO WORK
".write": "auth != null",
"real_db": {
// USERS
"users": {
"$user": {
".read": "auth != null",
"$other": {
// NOTE: I NEED TO COMMENT VALIDATE FOR OTHER FIELDS IN USER
// ".validate": false
},
"pushToken": {
".read": "auth != null",
".validate": "auth != null"
},
...
My runTransactionBlock is run on the path real_db/users/$uid and I am changing the value of pushToken. When setValue is run on this same path and modifying pushToken it works.

Error in syntax on Firebase database rules

{
"rules": {
"Users": {
"$user_id": {
// Grants write access to the owner of this user account
// whose uid must exactly match the key ($user_id)
".write": "$user_id === auth.uid"
}
}
"$businessName": {
".write": "root.child('Users').child(auth.uid).child($businessName).child('Permission s').val() === 'MODERATOR'"
}
}
}
This is giving me an error:
Error saving rules - Line 10: Expected ',' or '}'.
The error says I'm missing a bracket for some reason. Did I miss a comma or something?
As #Frank van Puffelen said I was just missing a comma before "$businessName".

Resources