3

I am trying to prevent storage abuse.My goal is like limit a user upload operation per day.So I deploy a storage onFinalize trigger and once a file uploladed the function detect a counter that using firestore is hit the limit or not.If is, store a millisec to CustomUserClaims like this:

//the user need to wait after this time to continue upload files (timeToUnlock = currentTime + additionalTime)
setCustomUserClaims(uid, {
    timeToUnlock: 1570509112055
})

And compare in rules

allow create: if request.time.toMillis() >= request.auth.token.timeToUnlock;

But every time when setCustomUserClaims i need to logout and login client again to update claims or claims won't update it just keeping previous value.I print customClaims to console the parameter are updated but seems parameter in rules are not updated.Anyone have better idea to fix this? Because if this doesn't work i have no idea to prevent this thank for any help.

console.log((await admin.auth().getUser(uid)).customClaims);
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
flutroid
  • 1,166
  • 8
  • 24
  • Changing the user profile on the server does not automatically invalidate ID tokens that already have been minted. The client will pick up the new token within an hour (the default time that an ID token is valid), or when you [force the client to refresh its ID token](https://firebase.google.com/docs/auth/admin/custom-claims#propagate_custom_claims_to_the_client). See https://stackoverflow.com/a/52732200, https://stackoverflow.com/a/54594212, https://stackoverflow.com/a/54594760 (not about custom claims, but it's the same behavior) – Frank van Puffelen Oct 08 '19 at 13:35

1 Answers1

11

What you're seeing is the expected behavior. Your backend code that updates the claims doesn't have the ability to force the client to see those claims immediately. According to the documentation:

After new claims are modified on a user via the Admin SDK, they are propagated to an authenticated user on the client side via the ID token in the following ways:

  • A user signs in or re-authenticates after the custom claims are modified. The ID token issued as a result will contain the latest claims.
  • An existing user session gets its ID token refreshed after an older token expires.
  • An ID token is force refreshed by calling currentUser.getIdToken(true).

The best you can do is write your client such that a change on the server triggers a change on the client to force a refresh of the ID token that will use the new claims. But that doesn't necessarily stop the client from using the old token until it finally expires.

If you want to limit uploads, it will be more secure and reliable to use a Cloud Functions trigger on each Storage upload, check to see if the file should be allowed, and delete the file if it violates your rules.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
  • Thanks for answer, but a thing I can't understand is why request.auth.token also not get update.bcause I want to prevent abuse before file create. – flutroid Oct 08 '19 at 07:29
  • 1
    The ID token that the user has is valid for an hour from when it's minted. The fact that you added a custom claim doesn't automatically invalidate the existing token. Only once the ID token is refreshed on the client, will the user (and thus security rules) get the new claim in their token. – Frank van Puffelen Oct 08 '19 at 13:32