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.
- A user registers, and is entered into the auth database, but marked as unverified
- He gets an email with a link to click which verifies him
- 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
Snippet background This is a very short snippet with a hack for dealing with when a user actions a verification ...
There's a really basic thing missing from Google Forms. What's missing ? A way of stamping responses with some sort ...
Here's how to set up a service account to access your firebase data base in admin mode. It's quite disjointed ...
Here's how to set up a service account to access your firebase data base in admin mode. It's quite disjointed ...
This'll be quite a long post, or maybe a series of them, as auth is always complicated. Lets first of ...
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 ...