I am updating my current login email using verifyBeforeUpdateEmail() function from firebase authentication, which successfully updates the email (in the Authentication) upon user verification of the email link received in their inbox. So my task is once that is done, I want to update my firebase firestore with the new email. How is this possible – as I only want to update the firestore only when the user has succesffully verified it.
Code snippet as follows:
void updateEmail(
String newEmail, BuildContext context, UserModel userData) async {
FirebaseAuth auth = FirebaseAuth.instance;
User? user = auth.currentUser;
try {
await user!.verifyBeforeUpdateEmail(newEmail);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
'You will shortly receive a confirmation link if you have entered a valid email. Please open your inbox and confirm'),
),
);
}
user = auth.currentUser;
if (user!.emailVerified) {
debugPrint('Only if the current user is verified');
UserModel newUserData = userData.copyWith(
mail: newEmail,
);
newUserData.updateFirestore();
}
} catch (e) {
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('$e'),
),
);
debugPrint(e.toString());
}
}
}
But with the above code regardless of new email verification, it gets updated in the firebase firestore (which I don’t want).
2
Answers
The actual change of the user’s email address happens out-of-band: in another app than the one that triggered the process, typically in the user’s email app. I don’t think there’s any signal to your client-side code when this action happens, nor any trigger to a Cloud Function/Eventarc for you to respond to.
This means that your only option is to detect the change in the client the next time it gets a new ID token, like when you get an event on the
userChanges
stream. When this happens: detect if the email address of the account is different from the one in Firestore, and if so update the record in Firestore.Similar to other out-of-band processes, you can force a refresh of the ID token by calling
reload
, which you can do when the app regains focus (i.e. after the user switches back to your app from their email client), when they tap a certain area/button/widget in your screen, or periodically – or a combination of all of these.The problem with calling
reload()
after the new email is verified is it causes the user to be logged outUnhandled Exception: [firebase_auth/user-token-expired] The user's credential is no longer valid. The user must sign in again.
, so you have to reauthenticate with the new email before calling reload. I was able to do this like so