Daniel D
Daniel D

Reputation: 998

Adding users to Firebase Database

I'm learning Firebase and creating my first project with it. I'm using FirebaseUI to simplify the authentication. I'm now working on the database and I need to start by adding my authenticated users to it. I've read all the documentation and I'm able to do this, but I'm wondering if I'm doing it the best way.

Since I'm using FirebaseUI and I'm not actually calling the signIn() or createUser() methods of Firebase Authentication myself, I thought the best way for me to add users would be to do it onAuthStateChanged()

usersRef = rootRef.child('users')

firebase.auth().onAuthStateChanged(user => {
  if (user) {
    let userRef = usersRef.child(user.uid)
    userRef.set({
      name: user.displayName,
      email: user.email,
      photoURL: user.photoURL,
      emailVerified: user.emailVerified,
    })
  }
}

This works fine but I'm concerned about two things:

1) This sets the user data every time the user is authenticated, even if the user already exists and nothing has changed. A simple page reload will rewrite the user to the database.

2) In order for this to work, the userRef location needs to be writable by the user. This would mean that the emailVerified in the userRef location isn't reliable because the user could potentially modify it himself. I could just rely on the emailVerified returned from onAuthStateChanged which the user could never modify, but I'm wondering if I'm just doing this wrong or if there's a better way.

A possible solution is described in a video found at https://www.youtube.com/watch?v=QEd2lEoXpp40. He creates two sections in the database: users and loginQueue. A user in users is only readable by the authorized user and loginQueue is only writable by an authorized user. When a user is authenticated, his data gets written to the loginQueue. He then uses the on() method to check for a child added to the loginQueue that matches their user.uid and somehow uses the update method to write to the user data to users. This works but I don't understand how. How can is the client able to send an update() to users\uid if it's only readable? You can see his code at 7:00 in the video. This has me stumped. This works but why.

I just implemented the technique as shown in the video and although it worked for him, I encountered a PERMISSION_DENIED error when trying to update the only readable user data. This is what I thought SHOULD happen but in his video he clearly shows this was not happening. Unless I'm missing something which I don't think I am, his method doesn't work anymore. Maybe it was a bug that was later fixed?

UPDATE: Thanks to Doug Stevenson for pointing me to Firebase Cloud Functions. I was able to completely solve my problem by creating a cloud function that responds when new users are authenticated. Here is my code:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.addUserToDB = functions.auth.user().onCreate(event => {
  admin.database().ref('/users/' + event.data.uid).set({
    name: event.data.displayName,
    email: event.data.email
  });
});

Upvotes: 4

Views: 7160

Answers (1)

Doug Stevenson
Doug Stevenson

Reputation: 317372

This is a common strategy.

  1. Authentication shouldn't happen too often. Also, if nothing changed in user record since the last write, nothing should actually happen. You don't pay for the bandwidth for client writes to the database.

  2. Split your user data up into two sections, one that's writable by the current UID, and the other that's not. That will prevent problems with users modifying data that you'd not like them to.

Alternately to this, set aside another location in your database where your clients can push commands to update data elsewhere, and use a Cloud Functions for Firebase trigger to read these commands, act on them with elevated privilege, checking for correctness, and delete them.

Upvotes: 3

Related Questions