Using another user identifier (UUID) than the user_id

I would also like to use UUIDs for associating data in our system with the users in Auth0. I prefer not to use the user_id as this is affected by the Auth0 account and idP configuration. For instance, if we have to move a tenant to his own Auth0 account, I will prefer not having to update all the data associated with the users of that tenant.

If Auth0 does not support the creation of UUIDs an alternative solution that I’m considering, is to call out to my own service to get such an UUID associated with the user. My next challenge then becomes that my general API verifies access tokens, but if I create this in a rule I will not have an access token yet and therefore I may need to put some other authentication on this end-point.

Do you have any suggestions for using UUIDs rather than the user_ids?

You can make use of the uuid NPM package in rules as a quick way to generate a UUID that can then be assigned to each user.

I’m including a sample rule that upon user login generates a UUID for the user, if one hasn’t been provided yet. After ensuring that every user is provisioned with a UUID the rule also exposes that information in any issued ID token or access token through the means of custom claim.

function (user, context, callback) {
  var uuid = require("uuid");

  user.app_metadata = user.app_metadata || {};

  var promise = Promise.resolve(1);

  if (!user.app_metadata.uuid) {
    user.app_metadata.uuid = uuid();

    promise = auth0.users.updateAppMetadata(user.user_id, user.app_metadata);
  }

  promise.then(() => {
    if (context.idToken) {
      // Include the uuid in the issued ID token if applicable
      context.idToken"http://example.com/uuid"] = user.app_metadata.uuid;
    }

    if (context.accessToken) {
      // Include the uuid in the issued access token if applicable
      context.accessToken"http://example.com/uuid"] = user.app_metadata.uuid;
    }
    
    callback(null, user, context);
  }).catch(callback);
}

Have in mind that the above rule is meant to be used along with the recent OIDC conformance flows and/or API Authorization features. With these flows, custom claims need to be added explicitly to the generated tokens and also have to use a namespace. (for more information check the OIDC-conformant authentication adoption guide)

If you’re not making use of these flows, which would be the case if you used /oauth/ro then you will be able to include custom claims in the issued ID Token by including it the requested scope scope=openid+uuid. In this scenario, namespaces are not required and the uuid claim would be returned if the user contained a matching property with that name either as a root property or as a property of app_metadata. The following revised rule should address the situation you mentioned regarding /oauth/ro:

function (user, context, callback) {
  var uuid = require("uuid");

  user.app_metadata = user.app_metadata || {};

  var promise = Promise.resolve(1);

  if (!user.app_metadata.uuid) {
    user.app_metadata.uuid = uuid();
    user.uuid = user.app_metadata.uuid;

    promise = auth0.users.updateAppMetadata(user.user_id, user.app_metadata);
  }

  promise.then(() => {
    callback(null, user, context);
  }).catch(callback);
}
2 Likes

Thanks @jmangelo. I can’t comment on your answer here, so posting another answer. I tried and it works. Before posting, I read this other post (https://auth0.com/forum/t/custom-user-id-using-long-uuid-hash/5611), which gives the impression that it is not supported.

So, I’m a bit afraid to just go ahead and use it although it seems to work. Maybe some support personnel can confirm/deny that this is the way to go?

Thanks,
Morten

I tried requiring uuid and it works. However, I read this post (https://auth0.com/forum/t/custom-user-id-using-long-uuid-hash/5611), which gives the impression that it’s not supported. I’m afraid to use it although it seems to work. Can someone from support confirm/deny this approach?

About adding it to the tokens, how does it work? Is the namespace required in the requested scope (or can I just write uuid) and do I need to allow it somewhere else? I don’t see it in the token until the second time, when it is added to the app_metadata. Using: https://tradeworks.eu.auth0.com/oauth/ro

I tried requiring uuid and it works. However, I read this post (https://auth0.com/forum/t/custom-user-id-using-long-uuid-hash/5611), which gives the impression that it’s not supported. I’m afraid to use it although it seems to work. Can someone from support confirm/deny this approach?

About adding it to the tokens, how does it work? Is the namespace required in the requested scope (or can I just write uuid) and do I need to allow it somewhere else? I don’t see it in the token until the second time, when it is added to the app_metadata. Using: https://tradeworks.eu.auth0.com/oauth/ro

The post you mentioned is about using an UUID as a replacement for the current user_id format and that is indeed not fully supported. This approach is about using an UUID in addition to user_id. Within an Auth0 account the user_id would still be the field that Auth0 treats as the unique user identifier, however, you would also have another unique field associated to each user using an UUID format. This allows greater flexibility, but also imposes more responsibility in order to do it right. In relation to the tokens, the rule was not tested with /oauth/ro so I’ll need to check it.

Thanks for the clarification. I managed to get the data into the token, by just setting the fields on the user object in the rule directly, e.g. user.uuid = myuuid;

Thanks for the clarification. I managed to get the data into the token, by just setting the fields on the user object in the rule directly, e.g. user.uuid = myuuid; I’m not sure if this is the right way, but I’ve seen something similar in a rule from the Authorization extension.

Thanks for the clarification. I managed to get the data into the token, by just setting the fields on the user object in the rule directly, e.g. user.uuid = myuuid; I’m not sure if this is the right way, but I’ve seen something similar in a rule from the Authorization extension.

Yep, I also updated the initial answer to have a rule aimed at /oauth/ro and the way to make sure the data is returned even in the first request is to do like you said and set the data at the root level also.