Tips on Using Firebase Database Rules to Validate a Node Property Value Against the User's Unique ID

I am currently utilizing the Firebase database and I am in the process of configuring rules to restrict write access to users whose uid matches the userId node of the object they are attempting to write, while still allowing the creation of new objects such as new posts if they do not already exist. Therefore, new posts are permitted, and editing one's own post is also allowed, but write access is denied if the post already exists but does not belong to the user.

Something along the lines of:

"posts": {
  ".write": "auth !== null && posts.post.userId.val() === auth.uid
}

or possibly something like

//where posts.post represents objectRef.objectUpdating
"rules":{
  ".write": " auth !== null && posts.post.userId.val() === auth.uid
}

Updating the posts.postid object can be achieved as follows:

firebase.database().ref('posts').child(id).update(updates)

Here is a glimpse of how posts are structured. Threads and forums follow a similar pattern.

  "posts": {
    "-KsjWehQ--apjDBwSBCZ": {
      "edited": {
        "at": 1504037546,
        "by": "ALXhxjwgY9PinwNGHpfai6OWyDu2"
      },
      "publishedAt": 1504035908,
      "text": "some post text",
      "threadId": "-KsjWehQ--apjDBwSBCY",
      "userId": "ALXhxjwgY9PinwNGHpfai6OWyDu2"
    },
    ...{post2},
    ...{etc}
  }

I hope this explanation is clear, any assistance would be greatly appreciated.

EDIT: I have managed to implement a check when the update or create method is invoked to verify if data.userId matches the auth.uid. Updating existing data now functions properly.

However, the create method is currently not functioning, and I am uncertain of how to allow update() to create new posts or threads as before without updating if the userId does not match auth.uid.

Rules below:

{
  "rules": {
    ".read": true,
    "users": {
      ".indexOn": ["usernameLower", "email"],
      "$user": {
        ".write": "auth !== null && $user === auth.uid"
      }
    },
    "forums": {
      ".write": false
    },
    "categories": {
      ".write":false
    },
    "$resource": {
      "$child": {
        ".write": "(auth !== null && auth.uid === data.child('userId').val()) || data.val() === null"
      }
    }
  }
}

Answer №1

I successfully got everything up and running. To illustrate using posts as an example:

"posts":{
  "$post":{
      ".write": "(auth !== null && auth.uid === data.child('userId').val()) || (!data.exists() && auth !== null)"
   }
}

If there is a more efficient method or if I am repeating myself or missing something, please feel free to leave a comment and inform me, as I am relatively new to firebase and value any feedback.

Below are my rules for reference. I am unsure whether I need to set ".write" to false following my other write rules to prevent any excess data from being written, or if that is taken care of automatically.

{
  "rules": {
    ".read": true,
    "users": {
      ".indexOn": ["usernameLower", "email"],
      "$user": {
        ".write": "auth !== null && $user === auth.uid"
      }
    },
    "categories": {
      ".write": false
    },
    "forums": {
      "$forum":{
        "lastPostId": {
          ".write": "auth !== null"
        },
        "threads": {
          ".write": "auth !== null"
        }
      }
    },
    "posts": {
      "$post": {
        ".write": "(auth !== null && auth.uid === data.child('userId').val()) || (!data.exists() && auth !== null)"
      }
    },
    "threads": {
      "$thread": {
        "$child":{
          ".write": "auth !== null"
        },
        ".write": "(auth !== null && auth.uid === data.child('userId').val()) || (!data.exists() && auth !== null)"
      }
    },
    "$resource": {
      "$child": {
        "$child2": {
          ".write": "auth !== null"
        },
        "userId": {
          ".write": "!data.exists()"
        }
      }
    }
  }
}

These are the updates being sent to update() to create a new post in the database:

const updates = {}
        updates[`posts/${postId}`] = post
        updates[`threads/${post.threadId}/posts/${postId}`] = postId
        updates[`threads/${post.threadId}/contributors/${post.userId}`] = post.userId
        updates[`users/${post.userId}/posts/${postId}`] = postId

firebase.database().ref().update(updates)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

troubleshooting problems with AJAX calls and routing in Angular

I am a beginner with Angular and I recently completed a tutorial on Single Page Application development using templates imported from PHP files, along with Resource and Route modules. Below is the JavaScript code from my project: (function(){ var app ...

Tips for querying multiple elements that share a common ID and verifying if the input has been modified

I have a series of text inputs that share a common id prefix but differ slightly at the end. Whenever a user enters text in any of these input fields, I want to trigger a function. Currently, I have this functionality implemented with the following code: ...

Displaying a loading screen while a jQuery ajax request is in progress

Currently, I am attempting to display a loading div while waiting for an ajax call to finish. Despite experimenting with various methods, I have not been able to consistently achieve the desired outcome. In my present code, everything functions properly o ...

Steps for integrating an Angular 2 App into Express.js as a view

I am currently working on developing an Angular 2 app that requires data from a script running on the server. To achieve this, I am attempting to integrate my existing Angular app as a view within an express application, similar to the process demonstrated ...

Fixing Half Screen Sidebars

I have a query regarding my coding problem. I am trying to create two pop-ups that occupy half of each screen. As I am new to JavaScript and jQuery, I want to ensure that I am doing it correctly. Is there a way for the left side to slide out from the left ...

Uploading multiple files simultaneously in React

I am facing an issue with my React app where I am trying to upload multiple images using the provided code. The problem arises when console.log(e) displays a Progress Event object with all its values, but my state remains at default values of null, 0, and ...

How can I incorporate multiple graphs into my AmCharts display?

I am new to using amcharts and have successfully implemented a code snippet to generate two graphs in a chart. The charts are loaded from an external data source specified in the code. var chart = AmCharts.makeChart("chartdiv", { "type": "serial", "d ...

The IDE is showing an error, but Jest is able to run it flawlessly

I recently created a Jest unit test for a TypeScript function called checkEmail, which internally uses showAlert. The showAlert function in the utils.ts file looks like this: export const showAlert = (message: string) => { toast(message); }; In my ...

What is the best way to include a property with a name in quotes to an object after it has already been declared?

Is there a way to include a property with a quoted name to an object after its declaration? Here's a simplified scenario: var Obj = {} Instead of: Obj.dog = "Woof!"; I want to achieve: Obj."dog" = "Woof!"; Similar to: var Obj = { "dog" : " ...

Despite successfully retrieving the response from the YouTube API Fetch, I am unable to access the items

Many questions regarding this issue focus on having the wrong key, but I believe my key is correct. Now I am confused whether the problem lies with the YouTube API or the fetch() method. In simple terms, I am sending the following request: export functio ...

Is there a way to utilize classes in various elements when other jQuery selectors are not functioning properly?

Could someone please clarify or provide an alternative solution to the following situation: The class fruit is present in two different tag elements, and one of these elements has the add class used in a jQuery selector. However, the alert box is not disp ...

Node.js/Express API Endpoint Ceases Functioning

In my Angular/Express.js app, there is a post method within my api.service.ts file: post(data: any, endpointUrl: string): Observable<T> { console.log("REACHED POST METHOD") return this.http.post<T>(`${this.apiUrl}/${endpoint ...

Can you provide me with a step-by-step guide on how to implement Stripe's Custom Payment feature

Currently in the process of creating a customized payment module for my django application and in need of some assistance. At the moment, I am using Stripe's Checkout for handling payments, but I find it restrictive as it doesn't allow for comple ...

Javascript: struggling with focus loss

Looking for a way to transform a navigation item into a search bar upon clicking, and revert back to its original state when the user clicks elsewhere. The morphing aspect is working correctly but I'm having trouble using 'blur' to trigger t ...

Utilize Jquery to locate and update the text of all div elements that have an empty id attribute

I need help with a task involving a list of divs, some with ids and some without. My goal is to identify all the divs within a specific class that have empty ids and change their inner text to say "no data available". Can this be done? My attempt using $( ...

Encountering an issue with Angular 5.2 application build on VSTS build server: Running into "CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory" error

Out of nowhere, the builds began failing with the following error : 2019-01-03T12:57:22.2223175Z EXEC : FATAL error : CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory error MSB3073: The command "node node_modules/webpack/bin/w ...

There appears to be an issue with reading the property 'toLowerCase' of an undefined element, and I'm having trouble identifying the error

The variables I have initialized (globally): var audio; var LANGUAGE; var audioArray; var MEDIAARRAY; var WORDS; var SOUNDARRAY; This specific line is causing the error: var audioId = MEDIAARRAY.audio.lowercase.indexOf(exObject['exerciseGetWordInpu ...

I am curious as to how this function is aware of the specific attribute that is being passed

I've been experimenting with a little application that fetches a list of movies from an API. You input a word and it returns all movies with that word in the title. Here's the code responsible for fetching the list: var getMovies = function (que ...

The script fails to execute upon the loading of the view

I am facing an issue with a simple JavaScript code that aims to target an element within an angular view: var buttons = document.querySelectorAll('.msg-type i'); console.log(buttons.length); When I run this code, it incorrectly prints out 0 on ...

Transform a collection of objects into an array

In my data array, I have various groups and types: const data = [ { groupName: 'groupName1', types: [ { name: 'name1', displayName: 'displayName1' }, { name: 'name2&apos ...