11

I have my security rules setup like so (in firestore console).

    service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {

      allow read: if request.auth.uid != null && request.auth.token.email_verified;
      allow write: if false; 
    }
  }
}

Firebase auto logs-in new users. Therefore, a recent user will have a non verified email address.

When the user verifies their email, I'm getting these results in my app.

Auth.auth().currentUser?.isEmailVerified // This is true

But when I make a request to the firestore I'm getting an error back that says that the user doesn't have enough permission to access that data.

When I sign the user out and then sign them back in, everything works fine.

My initial thoughts are that maybe there is a token that is not refreshed ? But this seems extremely confusing because I already refreshed the current user before attempting to make the request to firestore.

Auth.auth().currentUser?.reload()

I feel like I'm missing something.

Why are user's forced logged-in after they signup but then their email verification status isn't updated accordingly ?

Do we have to request-reauthentication ?

If so, what was the point of force log-in ?


This is getting extremely frustrating because I don't know how I'm suppose to manage my users.

Is signing in unverified user's something that we should do ? Wouldn't this lead to security concerns like user's making fake accounts and spamming your application.


Update

I read this non swift response which re-enforces my suspicion.

I'm going to test this solution tomorrow, the swift version of it is:

Auth.auth().currentUser?.getIDTokenForcingRefresh(forceRefresh: , completion: )

Docs for the method:

Retrieves the Firebase authentication token, possibly refreshing it if it has expired. Remark

The authentication token will be refreshed (by making a network request) if it has expired, or if forceRefresh is YES.

I'm guessing that in my case I have to force refresh because the token will not be expired.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
3366784
  • 2,423
  • 1
  • 14
  • 27

1 Answers1

12

It turns out that the token has to be refreshed as mentioned in the update above.

Here is how I solved my issue.

First I refresh the auth token

Auth.auth().currentUser?.getIDTokenForcingRefresh(true)

If that was successful, I then refresh the user.

Auth.auth().currentUser?.reload()

My issue was that I thought that reloading the user will refresh the token, I didn't imagine that things could be out of sync.

When I checked if the email was verified I got true but the firestore database needs a refreshed token for it to know that the email was verified.

3366784
  • 2,423
  • 1
  • 14
  • 27
  • Hey! I have exactly the same issue and I've tried to apply your solution but for some reason, it doesn't work - still have email_verified = false in the rules. Can you please provide the Firebase SDK version you use? Thanks. – Vadim S Jun 19 '18 at 16:56
  • @VadimSanko Yes, it's `4.10.0`. Make sure that you don't have a threading issue. I can share my code if you need it or better yet you can share your code. – 3366784 Jun 19 '18 at 20:33
  • @VadimSanko The `getIDTokenForcingRefresh(true)` method has a completion handler that is called a background thread, you need to dispatch the `currentUser?.reload()` method on the main thread. If you don't do that your current user might still be false because it's being refreshed on a background thread. – 3366784 Jun 19 '18 at 20:45
  • I have [the next code](https://iswift.org/playground?QjZ3mq&v=3). How can I run reload on the main thread? – Vadim S Jun 20 '18 at 05:00
  • It still doesn't work for me... Could you please share your piece of code around this issue? – Vadim S Jun 20 '18 at 06:30
  • @VadimSanko The code that you call inside of the update user completion handler should also be called on the main thread. My code is exactly the same, I'm guess it's a threading issue. `Thread.isMainThread` print that to see what thread you are in. – 3366784 Jun 20 '18 at 07:27
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/173452/discussion-between-vadim-sanko-and-3366784). – Vadim S Jun 20 '18 at 08:28
  • I confirm this solution does not work for me. I use the Flutter runtime, calling user.getIdTokenResult(true); and reload when the user has verified his email adds the email_verified claim to the token, but when requesting the firestore collection access, with a rule checking request.auth.token.email_verified == true, the request is denied. The only solution I have found is to remove the security check. It looks like a bug in Firestore. – Vilmir Aug 27 '21 at 18:49