Firebaseui-web: signInSuccessWithAuthResult callback does not work consistently with async code

Created on 6 Feb 2021  路  5Comments  路  Source: firebase/firebaseui-web


[REQUIRED] Describe your environment

  • Operating System version: Windows 10
  • Browser version: Chrome 88.0.4324.146 x64
  • Firebase UI version: 4.7.3
  • Firebase SDK version: 8.2.6

[REQUIRED] Describe the problem

Async code within signInSuccessWithAuthResult does not always finish, or the auth callback isn't finished yet when the async code starts (not 100% sure which one).

Steps to reproduce:

  1. Create Firebase UI widget with signInSuccessWithAuthResult callback and async code within.
  2. Sign up for a new user account with Google
  3. Watch as async code does not always finish running.

Relevant Code:

callbacks: {
  signInSuccessWithAuthResult: (authResult) => {
    const uid = authResult.user.uid;
    console.log("uid: " + uid);

    // Add a new document to Firestore
    db.collection("users")
      .doc(uid)
      .set({
        createdAt: firebase.firestore.FieldValue.serverTimestamp(),
        processed: false,
      })
      .then(() => {
        console.log("in promise");
        // Redirect to sign up step 2
        this.$router.push({ name: "Sign Up 2" });
      })
      .catch((error) => {
        console.error("Error adding document: ", error);
      });
    console.log("end of auth callback");
  },
},

It looks like the auth result does not finalize before the write to Firestore starts. I get this error sometimes (yes, my rules are set up correctly and sometimes I get the "in promise" line). But notice how it prints the error (or "in promise") after the "end of auth callback" log.

When it gets the error:
image

When it successfully writes:
image

need-more-info

All 5 comments

I don't think your issue is related to FirebaseUI. Something must be interrupting your logic. Is the page redirecting? If so, that could be the reason. When the callback triggers (assuming you are not redirecting), FirebaseUI will stop processing.

@bojeil-google Thank you for the insight. I think you're right. When I removed the this.$router.push({ name: "Sign Up 2" }); line it started to work consistently. I also tested it with return true; and that also lead to inconsistent results.

So now my question is, what is the proper logic for (after the asyc request has finished) redirecting to the next page when using the signInSuccessWithAuthResult callback?

EDIT: To be clear, when I do not put in any kind of manual redirect in the callback, the page does not redirect to the signInSuccessUrl, which I've set: signInSuccessUrl: "/signup-2",.

Hi @dhstack I am Yingqi came from Medium, sorry I just saw this. But the code I wrote is under a private repo and linked to a Firebase account that I have no access to no more right now, so I can't really link you there. But can you post your errors when you are using the previous async/await logic?

And I feel like the reason you got "end of" line before the "in promise" line is because the command to print the "end of" line is outside of your then block, since the whole adding-document block will take a bit longer, that command to prints the "end of" line will print first.

But anyways, did that line that prints "end of" line give you errors? Because I assume that with that console.log, signInSuccessWithAuthResult returns a void as a result, but it actually requires you to give it a true/false value type.

Can you try to do:

    callbacks: {
        signInSuccessWithAuthResult: async authResult => {
            try{ 
                  const uid = authResult.user.uid;
                  console.log("uid: " + uid);
                  await db.collection("users")
                    .doc(uid)
                    .set({
                      createdAt: firebase.firestore.FieldValue.serverTimestamp(),
                      processed: false,
                    })
                   router.push('/sth') // I remember I use the router in `next/router`, but I guess you will use whatever router you are using now? Bu the point is, in the situation you successfully add a doc, it will redirect you
            }catch(err){
                   console.error("Error adding document: ", error);
        }
          return false //just to make "signInSuccessWithAuthResult" happy bc it wants a boolean, so if the above operation failed, it will stay on where it is. 
        } 

I think one good practice if you want to run your own async logic on success and redirect is to do something similar to what @yingqi-chen described. You just return false. This means firebaseui will run the callback and since it returns false, it will not redirect to a signInSuccessUrl, thus not interrupting your success logic. You also have to ensure that no other redirect in your own logic interrupts your own logic.

@bojeil-google @yingqi-chen Thank you both for helping me get to the bottom of this. It looks like it's working as expected now. The main problem was not _explicitly_ returning false like this:

...
console.log("end of auth callback");
return false;

As an aside, the async/await syntax did not work (I didn't even get the "in promise" print out), so I left it with the then syntax.

Was this page helpful?
0 / 5 - 0 ratings