Auth0 Home Blog Docs

Add role to a user

jwt
auth0
login

#1

I want to add roles to a user (‘admin’ or ‘user’) based on their email address. In my application, I’m using accessToken but it’s not working. What I did:

  1. I created a rule in Auth0 (Set roles to a user). I want to add the role to accessToken payload:
function (user, context, callback) {
  user.app_metadata = user.app_metadata || {};
  var addRolesToUser = function(user, cb) {
    if (user.email && user.email.indexOf('email_to_check') > -1) {
      cb(null, 'admin');
    } else {
      cb(null, 'user');
    }
  };

  addRolesToUser(user, function(err, roles) {
    if (err) {
      callback(err);
    } else {
      user.app_metadata.roles = roles;
      auth0.users.updateAppMetadata(user.user_id, user.app_metadata)
        .then(function(){
          context.accessToken.role = user.app_metadata.roles;
          callback(null, user, context);
        })
        .catch(function(err){
          callback(err);
        });
    }
  });
}
  1. In my application I check if the user has the role ‘admin’:
     .antMatchers(HttpMethod.GET, "/api/admin").hasRole("admin");

But I can’t access the resources - Forbidden. What I’m doing wrong?
Thanks in advice!


#2

@alexluchian.92 in the above can it seems like you are properly updating the user’s app_metadata with that role, but not actually adding the role to the access_token. If I understand what you are trying to achieve it maybe worth modifying this a bit.

  1. The access_token is what we could hand off to a Resource Server (API) to determine what a requestor is authorized to do on behalf of the user. In the above I do not see how you are communicating to the application or API what the user is authorized to do. I am not going to assume how your application is built so I will give you maybe a few more details than you are asking for…

If your application needs to know the role of the user to properly display something on screen or do some other work it likely wants to know a few details about he user like role or some scope. You application should treat and access_token like an opaque string. So either you need to use the access_token to call an API to fetch the users access or use the id_token to communicate some of these details to the application. In either approach you will need to add some details to the token. The code you supplied above simply updates the user profile, but doesn’t actually add anything to the access or id tokens.

context.accessToken['https://yourdomain.com/claims/roles'] = user.app_metadata.roles;
context.idToken['https://yourdomain.com/claims/roles'] = user.app_metadata.roles;

Even better yet it would be nice, in the access_token, to map roles to specific scopes lining up to any scopes your API expects.

// Build some method to map roles to a de-duped list (space delimited) scope claim:
context.accessToken.scope = mapToRolesToScopeClaim(user.app_metadata.roles);
  1. Lastly, I noticed you are calling Management API to update the user’s profile with new information and doing so each time the user logs in. This maybe unnecessary depending on your implementation. Instead of persisting this role, which seems to be calculated, you might simply calculate it each time, never update the user profile, and simply return the id_token or access_token.