Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create user with Auth and write to Firestore at the same time

I have a scenario where I need to create a user using the Auth and add more info (such as name and type of business) to Firestore database. Firestore as transaction/batch operation but it is for Firestore only.

Is there a way where I can perform Auth operation such as create along with the Firestore data insert. Both operation has to succeed or fail. Right now I chain them but I would be worried that one fails and the other success in which a will need to handle gracefully.

Thank you

like image 343
Snake Avatar asked Mar 04 '18 21:03

Snake


3 Answers

When you are implementing Firebase authentication you can use a addOnCompleteListener or addOnSuccessListener and implement either the isComplete() or isSuccessful() methods. Inside one of these methods you need to create the user in your Firestore database. With other words, you will create the user only if the authentication is successful. So if isSuccessful() either all of the operations beneath one of that methods succeed, or none of them are applied.

The difference between those 2 methods is that we can that a Task is complete when the work represented by that Task is finished, regardless of its success or failure. There may be or may be not an error but we need to check for that. A Task is successful when the work represented by the task is finished, as expected, with no errors.

As o conclusion, there is no way to have a bulk solution. This is because there are 2 separate operations. So in order to be able to write user details in the database you need to be first successfully authenticated. If you want a rollback then you need to use again an addOnCompleteListener when you write user details to the database. If the you get an error just sin-out the user. There is no transaction/batch operation that can handle authentication and a database write operation as you described.

Edit:

Since you say you are using Firebase authentication, you can also use a function, written in Cloud Function to reach your goal. You can write a function that will run every time something in your project happens. One of those "things", is the creation of an user. With other words, you can execute your logic every time a new user is created. Here's an example:

exports.updateUserCount = functions.auth.user().onCreate((user) => {
  //Do what you need to do
});

Also, you can do the same thing on a user deletion, but registering a function using onDelete() method.

This will be very fast because there is no interaction with user's device. Please see more information about Firebase Cloud Functions.

like image 71
Alex Mamo Avatar answered Oct 02 '22 21:10

Alex Mamo


The best way to do scenarios like this is to use Firebase Cloud Functions. Cloud functions are triggered on various create/update/delete/write operations. You can trigger a cloud function on new user creation and then do the related Auth creation inside it.

https://firebase.google.com/docs/firestore/extend-with-functions

So in this case, you create user data first and in its success, call the Firebase Auth user creation. If you are worried about failure scenarios, you can remove the created user if in case the auth creation fails.

like image 33
Abdul Vajid Avatar answered Oct 02 '22 21:10

Abdul Vajid


I have solved this problem by using cloud function to create both auth user and firestore document. This way you can easily have some additional data required to create your user like invite code or things like that.

export const signUp = functions.https.onCall(async (data, context) => {
    const email = data.email;
    const password = data.password;
    const firstName = data.firstName;
    const lastName = data.lastName;
    const inviteCode = data.inviteCode;

    const userRecord = await admin.auth().createUser({
        email: email,
        displayName: (firstName && lastName) ? (firstName + ' ' + lastName) : (firstName ?? lastName),
        password: password
    });

    await admin.firestore().collection(constants.COLL_USERS).doc(userRecord.uid).set({
        inviteCode: inviteCode
    })
});
like image 24
Alexandr Avatar answered Oct 02 '22 20:10

Alexandr