How-to add a default role to Auth0 users

I’m using Auth0 inclusive the Authorization Extension for a private project. Now I wanted to implement the feature that my newly registered users receive a default role User. Unfortunately, I wasn’t able to find accurate documentation or code blocks that would shorten my implementation time. This missing documentation made me write my first blog article.

In this short post I want to depict how I managed to give my users a default role using Auth0 rules and the authorization extension.

Image the following scenario:

  • Roles: User, Admin
  • Each role has 1..n permissions, but it does not matter for this post
  • Every newly signed-up user should have the role User after the first login

Pre-Requirements:

Auth0 Rules Workflow:

  1. Load users policy to receive the roles (default authorization rule)
  2. Add the user to the role via the Authorization API if the role is missing
  3. Re-run the first rule to receive the updated policy

Step-by-Step:

1. Default authorization rule

The first rule is added by the Authorization extension itself. It did not change anything on this rule. The rules requests the user policy and appends the roles and permissions.

2. Add default role

This rule checks whether the user has already the default rule and if the role is missing it uses the Authorization API to add the user to the rule.

To use the API we need to request an access token first and append it to the authorization REST call. Via the Machine to Machine application from the second pre-requirement the rule requests the token from the authorization extension.

To make it easier for me, I simply copied the default authorization rule and adapted the rule were it was needed.

Because I have multiple applications in my Auth0 account and only want to add the role to MyWebApp, I check for the application name first.
I copied the Guid from the default role out of the authorization extension.

In case the user was added to the rule I save this information in the rule context to react on this event in the next rule (context.roleInitialized = true).

function (user, context, callback) {
  var _ = require('lodash');
  var EXTENSION_URL = "https://<domain>.eu.webtask.io/adf2e2f4b82783b57522e3b19dfc9201";
  var defaultRole = "c7dd23df-0b7c-41c2-80ae-7c3b065b570a";
  
  if (context.clientName === 'MyWebApp') {
    if(!_.includes(user.roles, 'User')) {
      requestToken(context, (error, response, body)  => {
        addDefaultRole(user, context, body.access_token, defaultRole, (err, res, body) => {
          if (err) {
             console.log('Error from Authorization Extension:', err);
             return callback(new UnauthorizedError('Authorization Extension: ' + err.message));
          }

          if (res.statusCode !== 204) {
            console.log('Error from Authorization Extension:', res.body || res.statusCode);
            return callback(
              new UnauthorizedError('Authorization Extension: ' + ((res.body && (res.body.message || res.body) || res.statusCode)))
            );
          }
          
          context.roleInitialized = true;
          return callback(null, user, context);
        });
      });
    } else {
      callback(null, user, context);
    }
  } else {
    callback(null, user, context);
  }

  function addDefaultRole(user, context, token, defaultRole, cb) {
    request.patch({
      url: EXTENSION_URL + "/api/users/" + user.user_id + "/roles",
      headers: {
        "x-api-key": "f5e1a9db9b9123049aa2390411289a3f9e2e7edaa5d7c88e451bf847dbf2e9441",
        "Authorization": "Bearer " + token
      },
        json: [
          defaultRole
        ],
      timeout: 5000
    }, cb);
  }
  
  function requestToken(context, cb) {
    request.post({
      url: "https://<auth0-authz-domain>.eu.auth0.com/oauth/token",
      header: {
        "content-type": "application/json"
      },
      json: {
        "client_id": "UPII3wYUdcVFGyzJFQPPSfUabkASsb2D",
        "client_secret": "oBPH1_F1tJqa9aizJCkQHaNJpFO2MlCQ3fHYlq6-6gR5NiDa-XY7WmPJCFlqXhGN",
        "audience": "urn:auth0-authz-api",
        "grant_type": "client_credentials"
      },
      timeout: 5000
    }, cb);
  }
}

3. Get updated user roles and permissions

In case the role was added in the previous step (context.roleInitialized = true) I need to update the permissions and roles of the user. Because I didn’t find a possibility to simply re-run a rule I copied the default authorization rule and did two modifications.
Firstly, I added the check whether the role was added in the previous rule.
Secondly, I removed some security checks, because these checks are already evaluated in the first rule and would be redundant now.

function (user, context, callback) {  
  if(!context.roleInitialized) {
    return callback(null, user, context);
  }
    
  var _ = require('lodash');
  var EXTENSION_URL = "https://<domain>.eu.webtask.io/adf2e2f4b82783b57522e3b19dfc9201";

  getPolicy(user, context, function(err, res, data) {
    if (err) {
      console.log('Error from Authorization Extension:', err);
      return callback(new UnauthorizedError('Authorization Extension: ' + err.message));
    }

    if (res.statusCode !== 200) {
      console.log('Error from Authorization Extension:', res.body || res.statusCode);
      return callback(
        new UnauthorizedError('Authorization Extension: ' + ((res.body && (res.body.message || res.body) || res.statusCode)))
      );
    }

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

    return callback(null, user, context);
  });

  // Get the policy for the user.
  function getPolicy(user, context, cb) {
    request.post({
      url: EXTENSION_URL + "/api/users/" + user.user_id + "/policy/" + context.clientID,
      headers: {
        "x-api-key": "f5e1a9db9b9123049aa2390411289a3f9e2e7edaa5d7c88e451bf847dbf2e9441"
      },
      json: {
        connectionName: context.connection || user.identities[0].connection,
        groups: user.groups
      },
      timeout: 5000
    }, cb);
  }
}

(Possible) Further Work:

  • Refactor rule code
  • Define default roles in the app_metadata from the application
  • Add the default role only on the first login. Right now, it checks for the role on every login.

Leave a Reply