0

After a user registers, we create a username for the user under /users child.

How can I setup my rules so that only the server can create new users and user data cannot be modified by other users.

Javascript

<script>
  var ref = new Firebase("https://myapp.firebaseio.com");
  var usersRef = ref.child('users');

  var usernameField = $('#usernameInput');
  var emailField = $('#emailInput');
  var passField = $('#passInput');
  $('#submitBtn').click(function() {
    ref.createUser({
      email    : emailField.val(),
      password : passField.val()
    }, function(error, userData) {
      if (error) {
        console.log("Error creating user:", error);
      } else {
        console.log("Successfully created user account with uid:", userData.uid);
        usersRef.push({
            uid: userData.uid,
            username: usernameField.val()
        });
      }
    });
  });

</script>

Current rules:

{
  "rules": {
    "users": {
      ".indexOn": "username",
      "$uid": {
        ".write": true,

        // grants read access to any user who is logged in with an email and password
        ".read": "auth !== null && auth.provider === 'password'"
      }
    }
  }
}
Community
  • 1
  • 1
Onichan
  • 4,476
  • 6
  • 31
  • 60

2 Answers2

3

To set up something so that "only the server can create new users", you can access your database using their Server SDK. This way, you can set rules that only apply to access to the database from the server.

However, if you want a web-based UI for admins to create new users, you need to write a Node.js or Java backend web server (utilizing the Server SDK). You can't use the client-side JS SDK, or Firebase hosting.

Just follow the instructions in the Server Side setup section of their documentation.

Then add the databaseAuthVariableOverride option to initializeApp:

var firebase = require("firebase");

firebase.initializeApp({
  serviceAccount: "path/to/serviceAccountCredentials.json",
  databaseURL: "https://databaseName.firebaseio.com",
  databaseAuthVariableOverride: {
    // maybe use something more descriptive and unique
    uid: "server-side-app"
  }
});

Then the following as your rules (warning: not tested):

{
  "rules": {
    "users": {
      ".indexOn": "username",

      // grants write access if the authenticated user is accessing 
      // via the Server SDK
      ".write": "auth != null && auth.uid === 'server-side-app'",

      // grants read access to any user who is logged in with an email/password
      ".read": "auth != null && auth.provider === 'password'"
    }
  }
}
zaim
  • 41
  • 3
0

There is no concept of "only the server" when you use Firebase. Each user writes their own data, so to secure that you need to use Firebase's User Based Security.

In this case the rules are fairly simple: you want each user to be able to only write to their own node. You can do this by modifying your rules to:

{
  "rules": {
    "users": {
      ".indexOn": "username",
      "$uid": {
         // grants write access to the owner of this user account
         // whose uid must exactly match the key ($user_id)
        ".write": "auth.uid === $uid",

        // grants read access to any user who is logged in with an email and password
        ".read": "auth.uid !== null && auth.provider === 'password'"
      }
    }
  }
}

Note that I copied the .write rule from the first example in the Firebase documentation on User Based Security. So it's probably a good idea to read that page (again), since it explains a lot more than just the answer to this question.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Sorry if this is obvious, but by allowing users to write their own data, what's to stop someone from creating endless posts, accounts, etc. Btw thanks for the great answers to all the Firebase questions on SO – Onichan Nov 06 '15 at 03:17