I have a StreamProvider that returns authStateChanges:
//Provider Watch Auth state Changes
@riverpod
class UserAuth extends _$UserAuth {
@override
Stream<User?> build() {
print('Stream Emitting');
return FirebaseAuth.instance.authStateChanges();
}
}
Now it emits correctly when I first sign in with google account, but if the user is already signed in with anonymous and I try to convert them to a google account user nothing is getting emitted because its going from signed in to signed in with a different provider meaning no state change is occurring, how I remedy this?
my method for creating or updating google sign in:
Future<void> signInWithGoogle() async {
try {
GoogleSignInAccount? googleUser = await GoogleSignIn().signIn();
if (googleUser == null) {
// Handle the case when the user cancels the Google sign-in
return;
}
final GoogleSignInAuthentication googleAuth =
await googleUser.authentication;
User? currentUser = FirebaseAuth.instance.currentUser;
if (currentUser != null && currentUser.isAnonymous) {
// User is signed in anonymously, link with Google account
AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
try {
await currentUser.linkWithCredential(credential);
await currentUser.reload();
User? updatedUser = FirebaseAuth.instance.currentUser;
// Pass the user's UID and email to update the user's document
if (updatedUser != null) {
createOrUpdateUserDocument(updatedUser.uid, updatedUser.email!);
}
} on FirebaseAuthException catch (e) {
// Handle specific FirebaseAuthExceptions if needed
print("Error linking with Google: $e");
}
} else if (currentUser == null) {
// User is not signed in, create a new account with Google credentials
AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
try {
final authResult =
await FirebaseAuth.instance.signInWithCredential(credential);
// Create a Firestore document for the user under the 'users' collection
if (authResult.user != null) {
await createOrUpdateUserDocument(
authResult.user!.uid, authResult.user!.email!);
}
} on FirebaseAuthException catch (e) {
// Handle specific FirebaseAuthExceptions if needed
print("Error signing in with Google: $e");
}
}
} catch (e) {
print("Error during Google sign-in: $e");
}
}
2
Answers
I got in touch with Firebase support and they told me:
"The behavior you're describing is expected because authStateChanges() doesn't distinguish between different sign-in methods; it simply emits a change whenever the authentication state changes. However, there's no built-in method to specifically detect an upgrade from anonymous to permanent user status"
They did say you can try combining authStateChanges() with idTokenChanges()as the other user suggestd but they also warned me its not full proof and will require the app to reload sometimes. turns out there is no fullprove way to do this so you will have to adjust your authentication flow, I hope firebase adds a method soon for this.
An auth state change listener only fires when the auth state changes, so when the user signs in or signs out. Other changes in the profile of the current user (such as linking another providers) don’t cause the auth state change listener to fire.
There’s another listener though for
idTokenChanges
, which fires for any change in the ID token. You’ll want to listen for that to detect other changes.