Firebase Auth Custom claims not propagating to client

我们两清 提交于 2021-02-16 05:19:11

问题


I have a user with UID 1 where the custom claims are set as,

frompos=true

I am setting new custom claims to this user from the ADMIN SDK for java the following way:

Map<String,Object> claims = new HashMap<>();

claims.put("frompos",false);

FirebaseAuth.getInstance().setCustomUserClaimsAsync("1", claims).get(10000,
                        TimeUnit.MILLISECONDS);

I print the claims on the server side to check if the claims are set:

UserRecord user = FirebaseAuth.getInstance().getUserAsync("1").get(10000,
                        TimeUnit.MILLISECONDS);

LOG.debug("user new claims " + user.getCustomClaims());

The result as expected is that the claims get set:

user new claims {frompos=false}

Now on the android sdk side, I have the user already logged in so I am refreshing the ID token manually to propagate the claims as the docs say (https://firebase.google.com/docs/auth/admin/custom-claims)

FirebaseAuth.getInstance().getCurrentUser().getIdToken(true).addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
         @Override
         public void onComplete(@NonNull Task<GetTokenResult> task) {
                    if(task.isSuccessful()){
                    Log.d("FragmentCreate","Success refreshing token "+(FirebaseAuth.getInstance().getCurrentUser()==null));

                    Log.d("FragmentCreate","New token "+task.getResult().getToken());

                        }
                    }
         }).addOnFailureListener(new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        Log.d("FragmentCreate","Failure refreshing token "+(FirebaseAuth.getInstance().getCurrentUser()==null)+" "+e.toString());
                    }
         });

Now I use the printed Id Token printed here and verify it on server side and print the claims from it

 FirebaseToken tokenTest = FirebaseAuth.getInstance(ahmedabadRepoApp).verifyIdTokenAsync(token).get(10000,TimeUnit.MILLISECONDS);

 LOG.debug("Token claims are "+tokenTest.getClaims());

But the claims printed here are:

{"aud":"ahmedabadrepo","auth_time":1514724115,"email_verified":false,"exp":1514730425,"iat":1514726825,"iss":"https://securetoken.google.com/ahmedabadrepo","sub":"1","frompos":true,"user_id":"1","firebase":{"identities":{},"sign_in_provider":"custom"}}

Thus the frompos value did not propagate to the client sdk even though I did refresh the Id token manually.


回答1:


I was having the same issue in angular - I set the claim using the Admin SDK on the server, but then they would not be in the user on the client.

Using the following I can see the claims in the payload:

  this.firebaseAuth.auth.currentUser.getIdToken().then(idToken => {

    const payload = JSON.parse(this.b64DecodeUnicode(idToken.split('.')[1]))

    console.log(payload);
    }

  )

b64DecodeUnicode(str) {
    return decodeURIComponent(atob(str).replace(/(.)/g, function (m, p) {
        var code = p.charCodeAt(0).toString(16).toUpperCase();
        if (code.length < 2) {
            code = '0' + code;
        }
        return '%' + code;
    }));
  }

Here is a good write up of this where I copied the above:

At the moment the client-side code must parse and decode the user’s ID token to extract the claims embedded within. In the future, the Firebase client SDKs are likely to provide a simpler API for this use case.

Relevant info from Firebase Docs:

Custom claims can only be retrieved through the user's ID token. Access to these claims may be necessary to modify the client UI based on the user's role or access level. However, backend access should always be enforced through the ID token after validating it and parsing its claims. Custom claims should not be sent directly to the backend, as they can't be trusted outside of the token.

Once the latest claims have propagated to a user's ID token, you can get these claims by retrieving the ID token first and then parsing its payload (base64 decoded):

// https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding
firebase.auth().currentUser.getIdToken()
  .then((idToken) => {
     // Parse the ID token.
     const payload = JSON.parse(b64DecodeUnicode(idToken.split('.')[1]));
     // Confirm the user is an Admin.
     if (!!payload['admin']) {
       showAdminUI();
     }
  })
  .catch((error) => {
    console.log(error);



回答2:


This might help: https://stackoverflow.com/a/38284384/9797228

firebase.auth().currentUser.getIdToken(true)



回答3:


The client sdk is caching the old token (old claims).

You should add a mechanism to refresh it after changing the claims (eg. push notification) or just wait for the old token to expires or user to lougout and login again.

It's explained here https://youtu.be/3hj_r_N0qMs?t=719

Edit

You can force the sdk to refresh the token using firebase.auth().currentUser.getIdToken(true)



来源:https://stackoverflow.com/questions/48042934/firebase-auth-custom-claims-not-propagating-to-client

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!