'Firebase Auth: Unable to update custom claims after setting them with createCustomToken

Details

If you use the function createCustomToken to sign in the user and setting his custom claim, updating the custom claims later using the function setCustomUserClaims will not update the claims even after forcing the idToken to refresh using the function firebase.auth().currentUser.getIdTokenResult(true)

How to reproduce?

Sign in the user on firebase using a custom token generated with the function createCustomToken including the custom claims

  firebase.auth().createCustomToken(uid, {myClaim: "test"}).then((customToken) => console.log(customToken))

Sign in the user on the frontend using the custom token

   // copy paste the customToken manually for testing
   firebase.auth().signInWithCustomToken(customToken)

Update the claim on the backend using setCustomUserClaims

   firebase.auth().setCustomUserClaims(uid, {myClaim: "updateTest"})

Refresh the idToken on the frontEnd and log the custom claims

   firebase.auth().currentUser
       .getIdTokenResult(/*force refresh*/ true)
       .then((idTokenResult) => {
          console.log(`custom claims`, idTokenResult.claims)
       })

You should see that the claim is still { myClaim: "test" } instead of { myClaim: "updateTest" }



Solution 1:[1]

Edit: This is actually an intended behavior. The claims set with createCustomToken have a higher priority. The doc mentions it here https://firebase.google.com/docs/auth/admin/custom-claims#set_and_validate_custom_user_claims_via_the_admin_sdk

Setting the custom claims separately at sign in instead of using the function createCustomToken to set them will allow you to edit these claims later.

Working code:

firestore
    .doc(`users/${uid}`)
    .get()
    .then((clientSnapshot) => {
      // give user the claims he has
      const { permissions = {} } = clientSnapshot.data()
     // use setCustomUserClaims to set the claims
      return auth.setCustomUserClaims(uid, { permissions })
    })
    // generate the custom token
    // ?? don't use createCustomToken to set permission as you won't be able to update them
    .then(() => auth.createCustomToken(uid))
    .then((customToken) => {
      // send the custom token to the frontend to sign the user in
      return res.status(200).json({ customToken })
    })

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1