Snippet background

This is a very short snippet with a hack for dealing with when a user actions a verification email from Firebase. The example is from a webapp client, but it applies to a common problem that is a gap in the auth workflow.

The flow

When someone registers using the email/password flow in firebase, there’s a handy extra step to deal with verification of an email address.

  1. A user registers, and is entered into the auth database, but marked as unverified
  2. He gets an email with a link to click which verifies him
  3. The auth database gets marked as verified

The problem

In a Firebase auth enabled client, changes in authenticated user is generally handled with the onAuthStateChanged event.

    auth.onAuthStateChanged((user) => {
handleUserChange(user)
})
onAuthStateChanged event

There’s also a less useful event that detects when an auth token changes.

However, a change in verification status doesn’t trigger these events, so if your app triggers the method to send an email verification, you won’t know when the user verifies as for some baffling reason, the change in that auth state doesn’t fire these change events.

currentUser.reload()

 
You can force a reload (which will pick up the changed verification state), but there is no way of knowing when to do that.
 

Hacky workaround

 
My workaround is simple to poll for changes from time to time, like this

export const emailVerification = () => {
const user = auth.currentUser
if (!user) throw new Error("tried to verify with no current user")
return user
.sendEmailVerification()
.then(() => {
wackyWaitForVerification()
return user
})
.catch((err) => {
console.log("failed to send verification", err)
return Promise.reject(err)
})
}
send email verification

And the recursive polling is done here

// because the authstate doesnt change when an email verification happens, we have do a hack
const wackyTimer = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
const wackyWaitForVerification = () => {
const user = currentUser()
if (!user) return null
if (!user.emailVerified) {
wackyTimer(5000).then(() => {
auth.currentUser.reload()
wackyWaitForVerification()
})
} else {
store.dispatch("authChange", { user })
}
}
waiting for verification

Another issue is that an unverified user may logout, and login again without triggering an email verify action, and use an email verification link sent in a previous session.

We need to also set this polling up on change of user if this happens

    auth.onAuthStateChanged((user) => {
handleUserChange(user)
if (user && !user.emailVerified) {
// this can happen if a new user logins who has never verified his email
wackyWaitForVerification()
}
})
unverified user logs on

And that’s the hack. Ping me if anybody has a better idea (especially the Firebase team if they happen to fix this little annoyance)

Related

firebase

Firebase auth snippet to deal with email verification

Snippet background This is a very short snippet with a hack for dealing with when a user actions a verification ...
submitted form

Using Firebase and Apps Script to link Google Forms reponses

There's a really basic thing missing from Google Forms. What's missing ? A way of stamping responses with some sort ...
firebase

Using a service account with Firebase in NodeJs

Here's how to set up a service account to access your firebase data base in admin mode. It's quite disjointed ...
firebase

Firebase service accounts on Node.js

Here's how to set up a service account to access your firebase data base in admin mode. It's quite disjointed ...

Firebase auth for graphql clients

This'll be quite a long post, or maybe a series of them, as auth is always complicated. Lets first of ...

Firebase JSON REST access library for Apps Script

The BigQuiz app uses Firebase for keep track of the question, category and game scores of individual players. In Firebase custom authentication with goa I showed ...