Flutter: How to listen to the FirebaseUser is Email verified boolean?

13,440

Solution 1

This verification isn't as straightforward as you'd hope. First, there is the problem of recognizing that the user has verified their email. Second, there is the issue that there isn't any sort of a notification you can listen to that will automatically trigger a change in your app.

Check this thread for info about emailVerified: https://github.com/flutter/flutter/issues/20390#issuecomment-514411392

I was only able to verify the user if I 1) Created their account, 2) Signed them in, 3) Then checked to make sure they verified their email.

final FirebaseAuth _auth = FirebaseAuth.instance;

var _authenticatedUser = await _auth.signInWithEmailAndPassword(email: _email, password: _password); 

//where _email and _password were simply what the user typed in the textfields.



if (_authenticatedUser.isEmailVerified) {
        //Verified
      } else {
        //Not verified
        }

Part 2: How do you get your app to recognize that the user has confirmed their email? Find a way to trigger the function that checks confirmation. A button would be easy enough. If you want it to see "automatic" then I guess you could create a timer that checks for email verification every 10 seconds or so.

Solution 2

I just faced the same situation in my app. My solution was to create a periodic timer into the initState method of a strategic route to hold the app until the e-mail is verified. It is not so elegant as using a listener but works fine.

bool _isUserEmailVerified;
Timer _timer;

@override
void initState() {
    super.initState();
    // ... any code here ...
    Future(() async {
        _timer = Timer.periodic(Duration(seconds: 5), (timer) async {
            await FirebaseAuth.instance.currentUser()..reload();
            var user = await FirebaseAuth.instance.currentUser();
            if (user.isEmailVerified) {
                setState((){
                    _isUserEmailVerified = user.isEmailVerified;
                });
                timer.cancel();
            }
        });
    });
}

@override
void dispose() {
    super.dispose();
    if (_timer != null) {
        _timer.cancel();
    }
}

Solution 3

I had the same problem with the latest version of firebase auth.

But I found out there is a function for reloading the current user which signed in

  Future<bool> get userVerified async {
    await FirebaseAuth.instance.currentUser.reload();
    return FirebaseAuth.instance.currentUser.emailVerified;
  }

Solution 4

Well I created a stream to handle this. Not so elegant but works. Use a StreamProvider.value() to handle events.

  Stream<userVerificationStatus> checkUserVerified() async* {
    bool verified = false;
    yield userVerificationStatus(status: Status.LOADING); 
    while (!verified) {
      await Future.delayed(Duration(seconds: 5));
      FirebaseUser user = await _auth.currentUser();
      if(user!=null)await user.reload();
      if (user == null) {
        yield userVerificationStatus(status: Status.NULL);
      } else {
        print("isemailverified ${user.isEmailVerified}");
        await user.reload();
        verified = user.isEmailVerified;
        if(verified)
        yield userVerificationStatus(status: Status.VERIFIED);
        else
        yield userVerificationStatus(status: Status.NOT_VERIFIED);
      }
    }
  }

Solution 5

In order for the app to recognise if the user has verified their email you can achieve this with a simple user.reload.

In order to test it yourself implement a button with onPressed code:

 FlatButton(
    child: Text("check"),
    textColor: Colors.white,
    onPressed: () async {
    try {
      FirebaseUser user = await _firebaseAuth.currentUser();
      await user.reload();
      user = await _firebaseAuth.currentUser();
        print( user.isEmailVerified); 
        

     } catch (e) {
      return e.message;
    }
}),
Share:
13,440
eifachtimon
Author by

eifachtimon

Updated on June 05, 2022

Comments

  • eifachtimon
    eifachtimon about 2 years

    My Idea: I want to use the Firebase Auth Plugin in Flutter to register the users. But before they can access the App, they have to verify their Email address. Therefor I push the Firebase users after registration to a verification screen. This is just a loading screen which tells the user that he has to verify his email.

    But now: How can I continuously listen, if the users email is verified or not and send him (when true) to the Homescreen?

    I'm new to Flutter and I don't know if I have to use a Streams or Observables or a while Loop or setState() or something else for such a boolean check. And I also don't know how to setup a solution.

    This is my basic code for register a user:

    import 'package:cloud_firestore/cloud_firestore.dart';
    import 'dart:async';
    
    class AuthService {
      final FirebaseAuth _auth = FirebaseAuth.instance;
      final Firestore _db = Firestore.instance;
    
      Future<FirebaseUser> get getUser => _auth.currentUser();
    
      Stream<FirebaseUser> get user => _auth.onAuthStateChanged;
    
      Future<FirebaseUser> edubslogin(String email, String password) async {
        try {
          final FirebaseUser user = await _auth.createUserWithEmailAndPassword(
            email: email,
            password: password,
          );
         
          await user.sendEmailVerification();
          
          //email verification somewhere here
        
          updateUserData(user);
          return user;
        } catch (error) {
          print(error);
          return null;
        }
      }
    

    I've tried this:

         if (user.isEmailVerified == true) {
            
            //go to Homescreen
            return true; 
          } else {
    
            //show verification screen(loading spinner)
            return false;
          }
    

    But I don't get a boolean value true out of isEmailVerified.

    What do I have to do?

  • Frank van Puffelen
    Frank van Puffelen almost 5 years
    The key here is that the app doesn't automatically get notified when the user verified their email address, so you'll need to check that yourself from within the app. To do this you'd force a reload of the user profile, so that you get the latest values from the server. With those you can then recheck the value of isEmailVerified.
  • TheAnimatrix
    TheAnimatrix about 4 years
    _auth should be the FirebaseAuth.Instance and userVerificationStatus is just a custom enum class
  • KylianMbappe
    KylianMbappe about 4 years
    This is brilliant! Thank you!
  • Ojonugwa Jude Ochalifu
    Ojonugwa Jude Ochalifu almost 4 years
    "This verification isn't as straightforward as you'd hope" It's as straightforward as straightforward can get.
  • Shalabyer
    Shalabyer over 3 years
    import 'dart:async';
  • theSpuka
    theSpuka about 3 years
    I totally agree with @OjonugwaJudeOchalifu. Can improved with Alisson's answer: Timer.periodic(fiveSec, (Timer t){ _auth.currentUser!..reload(); if(_auth.currentUser!.emailVerified){ //TODO: Proceed to specific page (route) }else{ //TODO: Toast something every five sec } });
  • Jamiel
    Jamiel over 2 years
    I can verify that your solution, in particular user.reload( ), is the correct way. I am using GetX to keep track of updating the widget. Worked like a charm. Although I definitely should make the function a future. Good work.
  • Jamiel
    Jamiel over 2 years
    Yes, worked like a charm. Only difference is I did not use a Future, just a bool function.
  • statHacker
    statHacker over 2 years
    Simple and works! A few updates for firebase_auth: ^0.18.3: I had to initiate these variables with values: bool _isUserEmailVerified=false;\n Timer _timer=Timer(Duration(seconds: 5), (){}); AND some of the functions have changed: await FirebaseAuth.instance.currentUser..reload(); //.instance.currentUser()..reload(); var user = await FirebaseAuth.instance.currentUser; if (user.emailVerified) { setState((){ _isUserEmailVerified = user.emailVerified; });