Authorization Extension roles not available

I’m just starting to use the Authorization Extension. I have created users, groups, roles, and permissions. I used the toggles for all three to save to the access token and generated a rule.

Where am I supposed to see them in my code? They are not present in the generated JWT and not present in the user profile when I get it from /userinfo.

2 Likes

@pswartwout when you enable those settings in the extension a rule should be generated once you click the Publish Rule button:

After that button has been pressed you should see a rule called auth0-authorization-extension in the rules view: https://manage.auth0.com/#/rules

The top three boxes should add this data to the JWT, but I think the rule generated is not adding it to the JWT. It seems to be adding it to the user profile only for the life time of the transaction here:

 // Update the user object.
    user.groups = data.groups;
    user.roles = data.roles;
    user.permissions = data.permissions;

    return callback(null, user, context);

I will file a bug for this with the crew, but you can fix this by adding a new rule or augmenting this rule by doing:

// Update the access_token alternatively you could update id_token by doing 
//context.idToken[]...
const namespace = 'https://yourdomain.com/claims/';
context.accessToken[namespace + 'groups'] = data.groups;
context.accessToken[namespace + 'roles'] = data.roles;
context.accessToken[namespace + 'permissions'] = data.permissions;

return callback(null, user, context);

As far as persisting the data to the user profile there are three additional toggles at the bottom of the Authorization API’s configuration section. These are for persisting the data to the profile. If any one of those is select the rule will output this:

saveToMetadata(user, data.groups, data.roles, data.permissions, function(err) {
      return callback(err, user, context);
    });

// ...

// Store authorization data in the user profile so we can query it later.
  function saveToMetadata(user, groups, roles, permissions, cb) {
    user.app_metadata = user.app_metadata || {};
    user.app_metadata.authorization = {
      groups: groups,
      roles: roles,
      permissions: permissions
    };

    auth0.users.updateAppMetadata(user.user_id, user.app_metadata)
    .then(function() {
      cb();
    })
    .catch(function(err){
      cb(err);
    });
  }
2 Likes

Thanks @sgmeyer, please update me when the bug is fixed. I have tried the three toggles at the bottom and did not notice any change to the user profile. Where should I be looking? I’m using lock.getUserInfo().

@pswartwout I would check the user profile in the dashboard. That profile will have an app_metadata field that should contain all of the groups, roles, and privileges associated with the user at the time of the last login.

Calling the getUserInfo() method will never return app_metadata. Auth0 use to allow this, but once we made the move to OIDC conformance we only support specific scopes and claims as defined here: Final: OpenID Connect Core 1.0 incorporating errata set 1

That makes it hard to do a client-side check when the user logs in. For example, to decide which home page to render. So either: (1) auth0 has to deliver the roles in the access token, or (2) I have to use the Authorization Extension API. Either of these would be done server-side to build my own user profile and deliver that through my own API, correct?

If your application cares about this information at the time of login you have the following choices:

  1. Add this data to the id_token since the access_token is meant to be consumed by an API/Resource Server. Then upon login have your client inspect the token.

2.a. Add these to an access token and have your client side call an API that returns those as part of the response. This is not always ideal, but if you want to use the access_token this would be a proper way to do it.

2.b. You get a token for the Management API with the scope to read the current user’s metadata and fetch those from the management api. This is the same as #2.a except you build fewer things.

If I were building this out I would chose option #1 since it is the easiest and requires the fewest changes. It is as simple as adding a single rule to follow your existing rule.

function (user, context, callback) {
  context.idToken['https://mycustomdomain.com/claims/authorization/roles'] = user.roles;
  context.idToken['https://mycustomdomain.com/claims/authorization/permissions'] = user.permissions;
  context.idToken['https://mycustomdomain.com/claims/authorization/groups'] = user.groups;
  callback(null, user, context);
}

Also, unless you are going to call the Management API to retrieve the user’s groups, roles, or privileges I wouldn’t persist that data to the user profile. This is almost always unnecessary and can create scaling issues with enough traffic to hit Auth0 API rate limits.