In the past year, I’ve been using Firebase quite a bit, and it became my exclusive backend since February at work, meaning I’ve been using it for personal projects quite a bit as well.
For the most part, I love what they’re doing, although writing security rules can be slightly unintuitive at first, and it’s also quite easy to fall into the trap of requesting too many reads when creating subscriptions.
But there’s one issue that’s caused me a fair bit of problems in the last few days:
So I ran into a couple of unexpected behaviours with this that I did not expect whatsoever, and I ended up wasting quite a few hours trying to figure out what the problems were. In summary, there were two behaviours on Firebase’s side that are quite unexpected (at least for noobs like me still deep-diving into this).
So just in case anyone else struggles with the same issues, I figured I’d write an article about the issue (because to be frank, I could not find much information about this).
1: Firebase auth does not push the change
Everything else in Firebase seems to be created around the concept of observable WebSockets, making it in particular easy to set up frontend observables with RxJs to make your web app reactive EVEN from the API layer!
Expecting the same behavior from Firebase.auth when I verify email addresses, I struggled to understand why my frontend did not automtically redirect users into the protected part of the site as my redirect middleware was instructed to do.
Well turns out having email set to verified does not warrant a push on
Fair enough, so I ended up with three possible solutions around this shortcoming:
- Users have to refresh or open the site in a new window to refetch user data
- Users prompt the site to fetch again (say, with a button)
- While the user is in the situation of being told to verify, short-polling can continuously check and automatically update the situation
Perhaps there are better solutions, but viable ones for my web application seemed to be one of those three.
I ended up going with the first one for the time being and continued developing until I encountered the second unexpected behaviour.
2. Firebase.auth does not automatically issue new Id Tokens on change
So now it’s starting to get quite funky. I’m using
.onIdTokenChanged() to subscribe for tokens, but a new token is not necessarily issued just because a user verifies their email.
This one is far funkier than the earlier behaviour.
What happened would be the following:
The user verifies email and refreshes the site.
firebase.auth().onIdTokenChanged returns a user object, containing user fields including
emailVerified and token.
emailVerified field (which I use for frontend logic) is set to true.
However, when I decode the token, I see that it has
emailVerified set to false.
Of course, this took me quite a bit of time to discover, as I naturally assumed the user object that I received from
firebase.auth() would be identical to the object wrapped in the id token.
Wow, so silly. Much wrong.
So I(foolishly) assumed
user.emailVerified is good enough, but I suddenly noticed requests failing when trying to alter fields protected by the following rule:
allow read, create, write: if request.auth != null && request.auth.token.email_verified == true;
So for this, there’s a couple of solutions, both of which are rather meh.
- Force users to log out and in when verifying their email
- Decode the
onIdTokenChanged(), check if token and user have different data, and if they do, request a new token manually by calling
For now, I ended up going with the second solution, though I’m not too happy about having to decode tokens in the frontend. I suppose I’m not sure exactly what I expected, since new tokens are only issued upon invalidation.
Perhaps my rant is unwarranted. In most authentication services I would expect this behaviour, but the other ways that Firebase makes data reactive in a completely seamless manner I was expecting authentication to work the same way.
Just be careful when implementing email verification! Things are not quite what they seem!