Search code examples
angularfirebasefirebase-authenticationangularfire2

Update Angular Firebase user after email verification


I am trying to find a way to refresh the current signed in Firebase user's information after a successful validation of their email address so they can continue to use the Angular 15 web application. I have a guard checking for validated emails...

The overall process is:

  1. User registers with email/password combination and is signed in.
  2. onAuthStateChanged is used to store the User object in localStorage.
  3. User is sent an email verification link
  4. User clicks on email verification link and returns to the web app in a new tab/window.
  5. User's Firebase Authentication email account is verified but the User object is not refreshed to reflect the change.

I'm trying to determine how best to update the current user to reflect the 'emailVerified' as true. Essentially, the localStorage object never gets updated to reflect the current state of the Firebase Authentication User object.

In a auth.service.ts service I have the following:

userData: any; //Save logged in user data

constructor(
    public afs: AngularFirestore, //Inject Firestore service
    public afAuth: AngularFireAuth, //Inject Firebase auth service
    public router: Router,   
    ) {
      // Listen for authentication changes and save User object to localStorage
      this.afAuth.onAuthStateChanged((user) => {       
        if (user) {
          this.userData = user;
          localStorage.setItem('user', JSON.stringify(this.userData));
          JSON.parse(localStorage.getItem('user')!);
        }
        else {
          localStorage.setItem('user', 'null');
          JSON.parse(localStorage.getItem('user')!);
        }
      });      
  }

  // Register the new user
  RegisterUser(userEmail: string, password: string) {
    return this.afAuth.createUserWithEmailAndPassword(userEmail, password)
      .then((result) => {
        this.SendVerificationMail();       
      });
  }

  // Send email verfificaiton
  SendVerificationMail() {   
    return this.afAuth.currentUser
      .then((u: any) => u.sendEmailVerification())
      .then(() => {
        this.router.navigate(['verify-email/sent']);
      });
  }

  // This is used within a AuthGuard to prevent un-verified accounts from continuing.
  get isVerified(): boolean {
    const user = JSON.parse(localStorage.getItem('user')!);
    return (user !== null && user.emailVerified !== false) ? true : false;
  }

Within a account-verify.component.ts component I have the following to handle the Custom email actions.

//Use the 'oobCode' from the querystring to validate the email
handleVerifyEmail(actionCode: string) {       
   this.authService.afAuth.applyActionCode(actionCode).then(() => {               
        
        // This is where I would think I would update the user somehow.
        
        }).catch((error) => {                    
         //Handle Error
        });
      }

I'm having a mental block as to how to ensure I have the most current information from the User's Firebase Authentication account.

I've tried:

this.authService.afAuth.currentUser.then((user) => {
    user?.reload();
  });

However localStorage never updates. Does the reload() not trigger onAuthStateChange?

Any insight or better ways to handle this are appreciated.


Solution

  • Does the reload() not trigger onAuthStateChange?

    As the name implies onAuthStateChanged triggers when the auth state has changed. A change in the email verification status is not considered an auth state change.

    If you want to detect all changes, use the similarly named onIdTokenChanged function to get notified when anything the ID token changes.