siefix
siefix

Reputation: 1016

Firestore - Managing User Sessions by revoking tokens

I'm looking into being able to manage user sessions - e.g. revoke tokens for bad actors and not let them to access data immediately (instead of after an hour/token lifetime).

In the guides it mentions being able to do comparisons vs stored "revoke time" in Security Rules. But it only mentions Firebase Realtime Database.

https://firebase.google.com/docs/auth/admin/manage-sessions#detect_id_token_revocation_in_database_rules

Save the refresh token revocation timestamp. This is needed to track ID token revocation via Firebase rules. This allows for efficient checks within the database.

{
  "rules": {
    "users": {
      "$user_id": {
        ".read": "$user_id === auth.uid && auth.token.auth_time > (root.child('metadata').child(auth.uid).child('revokeTime').val() || 0)",
        ".write": "$user_id === auth.uid && auth.token.auth_time > (root.child('metadata').child(auth.uid).child('revokeTime').val() || 0)"
      }
    }
  }
}

The key here is auth.token.auth_time

I tried to use this in Firestore Security Rules but it doesn't seem to be available.

Is this not possible in Firestore?

Upvotes: 0

Views: 500

Answers (2)

siefix
siefix

Reputation: 1016

Sebe had you were correct in needing to put request before request.auth.token.auth_time.

Even though its not shown in the documentation it seems to be there.

I had to create my own document during AuthOnCreate for each user when they first sign up so that there were fields for revoke_time (the designated key I made up, you can choose your own).

Then I stored these for each user in a revoked_tokens collection and could compare against in security rules.

function notRevoked() {
      return request.auth.token.auth_time > get(/databases/$(db)/documents/revoked_tokens/$(currentUser().uid)).data.revoke_time;
}

Firestore seems to be different that RTDB because you can't just use a default value of || 0. You actually need to have a value in the Firestore to compare against. I think this is because Firestore get() functions return null.

non-null rules.firestore.Resource the document, or null if it does not exist.

So if the document doesn't exist and you try to drill down into the get().data.someKey it will just error out and blow up your Security Rule. It would be like trying to do null.data.someKey

Upvotes: 1

Sebastian Vischer
Sebastian Vischer

Reputation: 1310

Maybe this works, in Firestore you have to set these rules on collections or documents.

service cloud.firestore {
   match /databases/{database}/documents {

     match /collection/{documentId} {
        allow read, write: if request.auth.uid != null && request.auth.token.auth_time > (root.child('metadata').child(auth.uid).child('revokeTime').val() || 0);
     }
   }
 }

I will try it myself if i find the time.

Upvotes: 2

Related Questions