firebase / flutterfire

🔥 A collection of Firebase plugins for Flutter apps.
https://firebase.google.com/docs/flutter/setup
BSD 3-Clause "New" or "Revised" License
8.66k stars 3.96k forks source link

[firebase_auth] The reload() function on a FirebaseUser doesn't seem to be working. #717

Closed kroikie closed 4 years ago

kroikie commented 4 years ago

Hey,

when calling the .reload() function on a FirebaseUser nothing seems to happen, as the data of the user I called reload() on doesn't change and the data of a user when calling FirebaseAuth.instance.currentUser() change nontheless, even when not calling reload().

What makes matter more confusing is that on the Stackoverflow Problem I opened "Frank van Puffelen", a Firebase Developer at Google said

If the user was already signed in, requesting auth.currentUser() does not refresh their profile data from the server.

which makes matter only more confusing, as this is not the case with my tested code.

Here is the example:

static stackOverflowProblem() async {
    FirebaseUser user = await FirebaseAuth.instance.currentUser();
    print("Name of User: ${user.displayName}"); //prints foo

    //Renaming the name from "foo" to "bar"
    UserUpdateInfo userInfo = UserUpdateInfo();
    userInfo.displayName = "bar";
    await _auth.updateProfile(userInfo);

    print("\nBefore calling user.reload:");
    print("Name of user: ${user.displayName}"); //prints foo
    print("Name of FirebaseAuth.instance.currentUser: ${(await FirebaseAuth.instance.currentUser()).displayName}"); //prints bar

    await user.reload();

    print("\nAfter calling user.reload:");
    print("Name of user: ${user.displayName}"); //prints foo
    print("Name of FirebaseAuth.instance.currentUser: ${(await FirebaseAuth.instance.currentUser()).displayName}"); //prints bar
  }

Output:

I/flutter (19989): Name of User: Foo
I/flutter (19989): 
I/flutter (19989): Before calling user.reload:
I/flutter (19989): Name of user: Foo
I/flutter (19989): Name of FirebaseAuth.instance.currentUser: bar
I/flutter (19989): 
I/flutter (19989): After calling user.reload:
I/flutter (19989): Name of user: Foo
I/flutter (19989): Name of FirebaseAuth.instance.currentUser: bar

The output i would assume, based on the answer from Frank van Puffelen and from my assumption about how the reload method should work, is:

I/flutter (19989): Name of User: Foo
I/flutter (19989): 
I/flutter (19989): Before calling user.reload:
I/flutter (19989): Name of user: Foo
I/flutter (19989): Name of FirebaseAuth.instance.currentUser: Foo
I/flutter (19989): 
I/flutter (19989): After calling user.reload:
I/flutter (19989): Name of user: bar
I/flutter (19989): Name of FirebaseAuth.instance.currentUser: Foo

Maybe also like this, as IMO FirebaseAuth.instance.currentUser() should always give the newest information, atleast that's how I think it works/should work.

[...]
I/flutter (19989): After calling user.reload:
I/flutter (19989): Name of user: bar
I/flutter (19989): Name of FirebaseAuth.instance.currentUser: bar

So any help with that, what is reload() for? Am I just confusing the method should work, or what is happening?! Please also look at the Stackoverflow Question. Thanks!

kroikie commented 4 years ago

@JSANL

The issue at https://github.com/flutter/flutter/issues/20390 has been closed and moved here. Future collaboration on this issue will be done here.

gabrielscr commented 4 years ago

Please fix this

iapicca commented 4 years ago

Hi @JSANL does the proposed solution fix the issue?

gabrielscr commented 4 years ago

I solved by using this:

Future updatePhoto(String photo) async { UserUpdateInfo userInfo = UserUpdateInfo();

userInfo.photoUrl = photo;
await _user.updateProfile(userInfo);
await _user.reload();
_user = await _auth.currentUser();

}

awhitford commented 4 years ago

@iapicca What might make sense is to introduce a Stream<User> listener so that User reloads can be broadcast. The main issue that I see is that widgets have stale information, and we need an easy way to refresh them.

livetalabs commented 4 years ago

The problem with not being able to get a change notification of isEmailValidated and also the value not refreshing after invoking reload() was driving me crazy for hours until I found the workaround in this post. Like others I feel the reload() method is not behaving like we expect it to but at least the workaround works. I can finally move on to my next problem.

feinstein commented 4 years ago

I sent a pull request with a solution for this, anyone interested please take a look at #1741.

Marvioso commented 4 years ago

I'm having the same problem and cannot get the FirebaseUser stream to update its data without signing out and signing back in. This is a truly awful user experience to have to create an account, verify the email, then have to log out and sign back in? How tedious! I expect that most users would abandon this authentication flow, I would. If it can't be automatic and reactive, then at least users should be able to trigger this update programmatically with the use of a button. If anyone has a solution that doesn't include signing out and back in, please share this? @feinstein if I understand your post above correctly, you suggested this change to the google team but you were met with reluctance to differentiate the Flutter API from the mobile and web SDKs. Any updates? They also said something about writing wrapper classes to provide this functionality, would you mind sharing a working example of how this can be done?

Cheers

Marvioso commented 4 years ago

Hi @livetalabs what was your workaround?

feinstein commented 4 years ago

@Marvioso yes, they are reluctant to approve a change in the API that doesn't reflect the Android and iOS ones, so they prefer that I publish it as a separete package, which I probably will.

For now you can just see my modifications on the the Pull-Request and understand how they work and make something similar for your project, that's how I am doing on mine and it works fine.

feinstein commented 4 years ago

I made a package to fix this, grab it here: firebase_user_stream

In the Readme I explain the issues and how the package fixes them, there are examples and etc, enjoy!

bean5 commented 4 years ago

So, I guess this should be closed as "Won't do?"

andrsdev commented 4 years ago

Same problem here, I need the firebase authStateStream to be working as expected on .reload();

ajaygautam commented 4 years ago

Ran into this issue too! I somehow seem to remember this working earlier!

Anyway... this is really serious and needs to be fixed ASAP. Bad user experience for users to be working with stale data!

erf commented 4 years ago

I mention a hack solution for missing onAuthStateChanged events in #2690 using rx.BehaviourSubject

feinstein commented 4 years ago

@erf you can also use firebase_user_stream

erf commented 4 years ago

@feinstein thanks, but i already have the oldUser, so i'm thinking it might be a performance hit, to do an extra query for it like you do. Also i had some timing issues when unlinking providers from the current user. I had to add some delay before calling currentUser, in order for providerData to be up to date. Have you done some testing on this? That is if all the data are present after updating some data?

feinstein commented 4 years ago

I am sorry but I don't understand what your issue is, I never had any timing issues, once the call to reload completes I get everything.

erf commented 4 years ago

@feinstein here is an example of what i do.

      await firebaseUser.unlinkFromProvider(PhoneAuthProvider.providerId);
      await firebaseUser.reload();
      _appState.forceAuthStreamUpdate();

After this i want to use firebaseUser.providerData from a new event and i should see "phone provider" is gone.

Before this i linked a phone account to an anonymous account.

Have you tested this?

feinstein commented 4 years ago

No I didn't, it's hard to test all the interfaces as they need network connections so can't be used on unit tests, but I can't see why it wouldn't work with my package, if you try it and have a problem, please file an issue for me please (but again, I expect it to work just fine).

erf commented 4 years ago

Ok, maybe i will test it out for my scenario and give some feedback.

erf commented 4 years ago

@feinstein it does seem to work! I'm curious if it is because of the delay with the initial await FirebaseAuth.instance.currentUser() call. In theory i should not need to call currentUser() to get the old value, since i allready have it, and it should be enough to call it to get the new value, that is after a call to await reload(), but yeah. Thanks anyway, it seem to work for now. I hope the Flutter team will improve this API at some point.

feinstein commented 4 years ago

That's not because of the delay, that's because of how reload works, it's counter intuitive and the Firebase team already said they aren't going to change it, that's why I made my package.

If you want to know the details of how it works, I explain it int he Readme of firebase_user_stream.

erf commented 4 years ago

I read your source code, and i was pretty much doing everything you did, except the initial call to get the "old user" since i already had it. I also did call reload on the "old user". So the only thing i can see is different is the delay with you retreiveing the "old user".

@feinstein in theory, you should be able to pass the oldUser as a parameter to reloadCurrentUser right?

feinstein commented 4 years ago

No, you also need to call the new user again to get it all updated, as I said, I explain this on the Readme.

I don't want to fill everyone's inbox with this, so if you have any further questions you can contact me on my email or in my projects repo.

awhitford commented 4 years ago

@feinstein Thank you for the firebase_user_stream package. Leveraging it was a snap and now my FirebaseUser instance is reliable.

Ehesp commented 4 years ago

As part of https://github.com/FirebaseExtended/flutterfire/issues/2582 we've introduced a userChanges stream, which triggers whenever auth state, id token or profile changes occur. Essentially, this acts as a way to obtain realtime changes on currently stateless functionality (such as updateProfile).

bulwinkel commented 4 years ago

Is it known yet which version of firebase_auth the userChanges stream will be released in?