Rules not executing in order

Hi Auth0 Community,

I suddenly have a problem where rules script not executing is not executing in correct order(they run asynchronously). These were fine and tested before, until I got some complaint from the users a month ago. Upon checking it was the rules that is not executing in proper order.

The 1st rules is meant to call auth0-authorization api to give roles to a user
The 2nd rules is meant to write metadata based on roles given on the 1st rules

On a side note, this was working fine for a year or so, then I start getting complaint about 2 months ago.

Hi @andre.hermanto93,

Can you do some testing / logging to demonstrate the behaviour? You can use the Realtime Webtask Logs extension to help. Anything you console.log() in a rule will show up in the realtime webtask logs interface.

1 Like

Hi @markd

So above are my 2 rules that doesn’t execute in order.

Assign role to selected users script is:

function (user, context, callback) {
  var acuteCare = '9da80d63-c29e-48bd-8cbb-a725f662df05';
  
  var emailsListAcuteCare = [
                             'test@test.com'
                          	];
  
  var accessGiven = [];

  if(emailsListAcuteCare.includes(user.email.toLowerCase())){
    accessGiven.push(acuteCare);
  }

  if(accessGiven.length > 0){
    var request = require("request");
    var options = { method: 'POST',
    url: 'https://URL/oauth/token',
    headers: { 'content-type': 'application/json' },
    body: '{"client_id":"ID","client_secret":"SECRET","audience":"urn:auth0-authz-api","grant_type":"client_credentials"}' };

    request(options, function (error, response, body) {
      if (error) throw new Error(error);
      var opt = { method: 'PATCH',
        url: `https://URL.au8.webtask.io/adf6e2f2b84784b57522e3b19dfc9201/api/users/${user.user_id}/roles`,
        headers: { 'content-type': 'application/json', 
              'authorization': `Bearer ${JSON.parse(body).access_token}` },
        body: JSON.stringify(accessGiven)
    };

    request(opt, function (er, response, body2) {
      console.log("This should come 1st");
      if (er) throw new Error(er);
     });
   });
  }
  
  callback(null, user, context);
}

Then my auth0-authorization-extension script is:

function (user, context, callback) {
  var _ = require('lodash');
  var EXTENSION_URL = "";

  var audience = '';
  audience = audience || (context.request && context.request.query && context.request.query.audience);
  if (audience === 'urn:auth0-authz-api') {
    return callback(new UnauthorizedError('no_end_users'));
  }

  audience = audience || (context.request && context.request.body && context.request.body.audience);
  if (audience === 'urn:auth0-authz-api') {
    return callback(new UnauthorizedError('no_end_users'));
  }

  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.permissions = data.permissions;

    // Store this in the user profile (app_metadata).
    saveToMetadata(user, data.groups, data.roles, data.permissions, function(err) {
      console.log("This should come 2nd");
      return callback(err, 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": "API KEY"
      },
      json: {
        connectionName: context.connection || user.identities[0].connection,
        groups: user.groups
      },
      timeout: 5000
    }, cb);
  }

  // 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 = {
      permissions: permissions
    };

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

Then upon execution the 2nd always executed first. Here’s the screenshot of the logs

Hi @markd,

Is there any update on this?

Cheers

The callback of the first rule

callback(null, user, context);

is outside of the request {...} , so that calling is executed without waiting for the request() to finish, as the request runs async.
It should be inside that request, like this:

request(opt, function (er, response, body2) {
  console.log("This should come 1st");
  if (er) {
    throw new Error(er) 
  } else {
    callback(null, user, context);
  }
 });

But also note, since you actually have 2 request in your first rule: these requests also don’t wait for each other, so you never know which of the two requests will finish first. Might make sense to call this in a nested as well.

2 Likes

Hey there!

As this topic is related to Rules - Hooks - Actions, I’m excited to let you know about our next Ask me Anything session in the Forum on Thursday, January 18 with the Rules, Hooks and Actions team on Rules & Hooks and why Actions matter! Submit your questions in the thread above and our esteemed product experts will provide written answers on January 18. Find out more about Rules & Hooks and why Actions matter! Can’t wait to see you there!

Learn more here!

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