Access all users in a Rule to set attribute and validate uniqueness

Hello. I’m trying to set a unique 6 digit hex id on all of our users at login with a rule. I can do that fine in the rule with the exception of checking the uniqueness of that id against the other users in our tenant. I can’t seem to figure out how to access all other users in the rule so that I can loop over them and check said attribute. Any help would be appreciated!

Hi @jasonmwnf,

Welcome to the Community!

Can you provide some details regarding what you have done so far? The code of your rule would be helpful.

@markd, Thank you for the welcome! Here is the code so far. This works fine. It sets the short_id to a 6 digit hex. The missing piece is checking the short_id against the other users to make sure it’s unique:

function (user, context, callback) {
  user.user_metadata = user.user_metadata || {};
  user.user_metadata.short_id = user.user_metadata.short_id || "nurse-" + hex(6);
  context.idToken['https://mydomain.com/short_id'] = user.user_metadata.short_id;
  
  function hex(n){
   	n = n || 6;
   	var result = '';
   	while (n--){
    	result += Math.floor(Math.random()*16).toString(16).toUpperCase();
   	}
   	return result;
  }

  auth0.users.updateUserMetadata(user.user_id, user.user_metadata)
    .then(function(){
        callback(null, user, context);
    })
    .catch(function(err){
        callback(err);
    });
}

Setting ID using rule is possible but you cannot assure the uniqueness of that ID. As you won’t be able to access all users in rule to verify uniqueness of the newly created ID every time. It also doesn’t seems feasible to pull all users and iterate them every time.
There are two possible solutions of you problem.
1- You can use already created user_id in auth0 profile.
2- You can fetch current system time stamp up to Milli seconds and update it in user profile. It will be unique every time so you don’t need to worry about uniqueness.

So, it’s not possible to access all other users in an Auth0 tenant from within a rule? Also, I wouldn’t being pulling the users everytime. Pseudo code:

  • check to see if current user has a short_id
  • if not:
    • generate a 6 character short_id
    • grab other users.
    • iterate over other users and compare short_id for uniqueness
    • if its all good, assign the short_id to current user

So, the code that required the other users would only run (once) for users that didn’t have a short_id, and not at all for users that already have one. Either way, it’s all moot if you can’t access the other users in a tenant. Thank you for your response.

If this can work (I haven’t tested it myself), you shouldn’t have to iterate over the other users. Just do a query against the /users endpoint for user_metadata.short_id === user.user_metadata.short_id.

Is the 6 hex char format a hard requirement? As @rashid779939 mentioned, this is easier if you can just assign a guaranteed unique ID from the start, and avoids the search as well as the possibility of blocking on the rules pipeline if something goes wrong.

It doesn’t necessarily need to be in 6 hex char format. But, some sort of shorter, human readable id would be best. Here’s the use case: All of the models in our app have uuid’s. But, a lot of those models are used by third parties for research. So, in our rails app we generate a ‘short_id’ that is easy to glance at, but is still unique to each model. We can’t do that with our users as we don’t have a users table. We use Auth0 for our users exclusively. So, if I can get some sort of easily readable, shorter id that can be guaranteed to be unique, I think my requirements would be met.

You should be able to do something like this: Here I am searching for all users with an email address ending in sr2.ca. Replace with equivalent logic searching for the new short_id. You’ll need to add some iteration to keep generating new short_id values until you find a unique one.

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

  var params = {
    search_engine: 'v3',
    // REPLACE WITH QUERY FOR short_id
    q: 'email:*@sr2.ca'
  };

  management.getUsers(params, function (err, users) {
    // DO SMARTER THINGS WITH SEARCH RESULTS
    console.log(users);
  });

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

I’m not done yet. But, I’m close enough that I’d definitely consider this the solution^. Thank you for your help!

1 Like

Ok, looks like I spoke too soon. Here’s some code that works with one iteration. The problem is as soon as I try and wrap the portion indicated in a loop, it stops working (The loop being for checking the generated short_id for uniqueness). I’m pretty new to Javascript, but I suspect this is some sort of callback problem? I got a blocked event loop error Any ideas?

 function (user, context, callback) {
      var id_not_unique = true;
  
  function hex(n) {
    n = n || 6;
    var result = '';
    while (n--){
      result += Math.floor(Math.random()*16).toString(16).toUpperCase();
    }
    return result;
  }
  
  var ManagementClient = require('auth0@2.9.1').ManagementClient;
  var management = new ManagementClient({
    token: auth0.accessToken,
    domain: auth0.domain
  });
  
  // LOOP WOULD START HERE
  var short_id = `nurse-${hex(6)}`;
  var params = {
    search_engine: 'v3',
    q: `user_metadata.short_id:"${short_id}"`
  };
	
  management.getUsers(params, function (err, matched_user) {
    if (Object.keys(matched_user).length === 0) {
     	id_not_unique = false;
      user.user_metadata = user.user_metadata || {};
    	user.user_metadata.short_id = user.user_metadata.short_id || short_id;
    	context.idToken['https://mydomain.com/short_id'] = user.user_metadata.short_id;
      
      auth0.users.updateUserMetadata(user.user_id, user.user_metadata)
        .then(function(){
            callback(null, user, context);
        })
        .catch(function(err){
            callback(err);
        });
       } 
   });       // LOOP WOULD END HERE
 }

I created a new post for this as I suspect this one being marked as ‘solved’ is giving it less visibility. Thanks again for your help so far everybody.

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