Accessing the permissions array in the access token

How does one go about accessing the list of permissions returned with the access token?

I am using the react-auth0-spa module (containing the Auth0Provider functional component) in combination with the PrivateRoute component (see https://github.com/auth0-samples/auth0-react-samples/blob/master/01-Login/src/components/PrivateRoute.js) and it isn’t clear how to de-reference the permissions array.

I have a route for example the Settings page that should only be accessed by Super Admins that have the required permissions (for example read:settings). So it is a route that not only requires an authenticated user but also one that has the appropriate permission.

I am thinking I need to augment the PrivateRoute component to have an additional permissions check for the Settings page and redirect to a Not Authorized page if the user doesn’t have the required permissions. I have confirmed that the permissions array is being returned but it isn’t clear to me how I would access this array.

Any pointers appreciated.

Cheers

1 Like

Not sure about the React specific part, but just note that access tokens are by design not meant to be parsed by the client, they’re only meant for the backend / resource server (the audience for which it has been issued). If the permissions are needed in the client, then that should be a separate API call, or it could be added to the ID token (which is explicitly meant for the client to be used) via custom claims through the Auth0 Rules. The permissions can be read within a rule through the Management API.

2 Likes

Thanks for your quick reply @mathiasconradt.

I do need to access the permissions on the client to know whether to allow the user to access a protected page (a page that requires a certain permission over and above being authenticated). Once I turned on “Enable RBAC” and “Add Permissions in the Access Token” in the configuration settings for my logical API and also specify this API in the “audience” parameter of the Auth0Provider react component the permission array is passed back along with the access token.

Note that the permissions array does not come back with the ID token as you mentioned but rather with the access token.

I can get a reference to the Auth0Client instance from inside my react component and I do see that the token gets cached within it.

I’m checking out this tutorial now: Role-Based Access Control

@ryantomaselli Understood, so you would need to add it as custom claims into the ID token via Rules, as per my previous answer. Are the links provided sufficient to get it to work?

Okay so no touchy on the permissions returned in the access token…got it. I’ll proceed with fully absorbing the links you sent. Thanks!

2 Likes

Alright I think I have the path clear, but to confirm:

  1. I create a rule (from a blank one)
  2. Make an ajax request to the /users/user_id/permissions end point inside of the rule
  3. Augment the idToken with the list of permissions

Something along these lines:

function (user, context, callback) {
  var request = require("request");
  var options = {
    method: 'GET',
    url: 'https://' + API_DOMAIN + '/v2/users/' + user.user_id + '/permissions',
    headers: { authorization: 'Bearer ' + MGMT_API_ACCESS_TOKEN }
  }

  request(options, function (error, response, body) {
    if (error) throw new Error(error);

    var namespace = 'https://mydomain/';
    var permissionsArr = response.map(function (permission) {
      return permission.permission_name
    })
    context.idToken[namespace + 'user_authorization'] = {
      permissions: permissionsArr
    }
    callback(null, user, context);
  })
}

I’m not clear on how to get values for API_DOMAIN and MGMT_API_ACCESS_TOKEN in this context.

@mathiasconradt am I on the right track here?

In the Management console (at Auth0 Management API v2) when I plug in the user_id and add in defaults for the other fields (just to be sure) I’m getting the following response and unclear why:

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Query validation error: 'Additional properties not allowed: _'.",
  "errorCode": "invalid_query_string"
}

The request URL looks looks like this:
https://dev-j63rw92b.auth0.com/api/v2/users/auth0|5d1fe3d83008ef0ded9f3865/permissions?per_page=50&page=0&include_totals=false

Oh I see now “that rules will also have access to several modules defined globally, including auth0” so should be able to call getUserPermissions inside the rule.

But this is confusing…I found an example (at https://kisdigital.com/2018/07/12/leveraging-auth0-rules-and-hooks/) in which a call to the auth0 node module is made like so (and it works):

auth0.users.updateAppMetadata(user.user_id, user.app_metadata)

So I get happy and think perhaps I can use something like so (but to no avail):

auth0.users.getUserPermissions(user.user_id)

I get the following error:

Code generated an uncaught exception: TypeError: auth0.users.getUserPermissions is not a function

What am I doing wrong here? Why is updateAppMetadata available but not getUserPermissions?

Unfortunately this is a bit confusing, I admit (already mentioned it to our documentation team):

The Rules engine in Auth0 isn’t using the latest node-sdk as referenced in the API docs on Github by default.
In order to enforce the latest version, you need to require it manually like below. Then the docs as on https://auth0.github.io/node-auth0/module-management.ManagementClient.html#getUserPermissions apply.

function (user, context, callback) {

  var ManagementClient = require('auth0@2.17.0').ManagementClient;
  var management = new ManagementClient({
    token: auth0.accessToken,
    domain: auth0.domain
  });

  // example params taken from docs page, adjust as needed
  var params = { id: user.user_id, page: 0, per_page: 50, sort: 'date:-1', include_totals: true };

  management.getUserPermissions(params, function (err, logs) {
    if (err) {
      // Handle error.
    }
    console.log(logs);
  });
}

Update/edit: one thing to note is that this rule would call the management API on every authentication request (this might lead to rate-limit issues). A way to optimize it would be to pre-calculate a user’s permissions and store it in the user’s app_metadata. The updating could be triggered by the Auth0 Authentication API Webhooks, listening to the respective events.

3 Likes

Alright thanks @mathiasconradt I’m finally cooking with butter over here…

I’m pasting my rule that augments the idToken with user permissions here for others:

function (user, context, callback) {
  var map = require('array-map');
  var ManagementClient = require('auth0@2.17.0').ManagementClient;
  var management = new ManagementClient({
    token: auth0.accessToken,
    domain: auth0.domain
  });

  var params = { id: user.user_id, page: 0, per_page: 50, include_totals: true };
  management.getUserPermissions(params, function (err, permissions) {
    if (err) {
      // Handle error.
      console.log('err: ', err);
      callback(err);
    } else {
      var permissionsArr = map(permissions.permissions, function (permission) {
        return permission.permission_name;
      });
      context.idToken[configuration.NAMESPACE + 'user_authorization'] = {
        permissions: permissionsArr
      };
    }
    callback(null, user, context);
  });
}

Note that I am using a global config settings (found on the Rules home page) to set the configuration.NAMESPACE value.

My next step will be reading these permissions on the client side…stay tuned.

You can use the getIdTokenClaims method of the auth0Client to get at the permissions added in the rule.

7 Likes

This topic was automatically closed 15 days after the last reply. New replies are no longer allowed.