I'm using the Firebase web SDK v4.0.0 and I'm trying to ensure that only unique usernames (a string chosen by the user) are stored in the database. I've set up email/password authentication and that works fine. I've also set up rules to ensure that the username is unique. The database write relies on the authentication passed from when the user is created. However, when a collision occurs at the write to database stage (i.e. the chosen username isn't unique), the user has already been created.
It feels like the correct thing to do is a transaction that includes the user creation/authentication and database write but I can't find any info on this in the docs. Has anyone tackled this situation before?
Here's my rules file:
{
"rules": {
"users": {
"$userID": {
"username": {
".read": true,
".write": "!data.exists() && newData.exists()",
".validate": "newData.isString()"
}
}
},
"usernames": {
"$username": {
".read": true,
".write": "!data.exists() && newData.exists()",
".validate": "newData.isString() && newData.val() == root.child('users/' + auth.uid + '/username').val()"
}
}
}
}
and the relevant bit of my sign up code:
var ref = firebase.database().ref();
var userData = {};
userData["usernames/" + username] = firebase.auth().currentUser.uid;
userData["users/" + firebase.auth().currentUser.uid] = {
username: username,
signupdate: firebase.database.ServerValue.TIMESTAMP,
uid: firebase.auth().currentUser.uid, // store it here for easy comparison later
displayname: displayname,
email: email
};
// Do a deep-path update
ref.update(userData, function(error) {
if (error) {
console.log("Error updating data:");
console.log(error);
}
});
BTW I'm doing a client side check before the form is submitted to prevent duplicate usernames being submitted in my web form. This server-side approach is to try to prevent a malicious user using the console to bypass my check and submit 'unhelpful' duplicates.