The way I have seen games do it, is by offering a user to link accounts. That is, after logging in with one provider, you are given the option of linking by logging into a second. In the link above, after the second login, the user would no longer have write access to their existing record (the
and provider would change). One work around would be to let the user remember a key to unlock the record without a login.
"users": {
"$userid": {
// Require the user to be logged in, and make sure their current credentials
// match at least one of the credentials listed below, unless we're creating
// a new account from scratch.
".write": "auth != null &&
(data.val() === null || (newData.key === data.unlock && newData.unlock === null) ||
(auth.provider === 'facebook' && auth.id === data.child('facebook/id').val() ||
(auth.provider === 'twitter' && auth.id === data.child('twitter/id').val()))"
}
}
Now someone can write to the users record, as long as their write includes a key record which matches the unlock record (IMPORTANT: and they remove the unlock record so its one use only)
So the flow then becomes
1. login a new user as normal
2. if the user choses to link account
2a. write a long random unguessable KEY in $userid.unlock, and remember it in the client application
2b. let the user log into a new provider
2c. let the user write a mapping record from the new provider to the existing $userid
2d. update() (or set the whole record) the new provider credential in the $users record AND set the key to the KEY value AND set the unlock record to null.
For example, something like
var updatePayload = {
key: <KEY>,
unlock: null
});
updatePayload[ref.getAuth().provider] = ref.getAuth().id;
ref.child("users/<myuserid>").update(updatePayload);
*its important the unlock get wiped every time its used, otherwise after an unlock the user record can be updated by anyone, so you want the key to be one use only
Now you can generalize this idea to allowing a user to create two independent user records, then merging them later, by leaving keys in the appropriate places before initiating a merge and updating the various pointers.