Update user_metadata example from API docs not working

function(user, context, callback){
  user.user_metadata = user.user_metadata || {};
  // update the user_metadata that will be part of the response
  user.user_metadata.preferences = user.user_metadata.preferences || {};
  user.user_metadata.preferences.fontSize = 12;

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

After many attempts to add metadata to my user object, I decided to paste the example above into my rules (which is directly from the API docs), and it does not seem to work. The fontSize property does not appear.

Thus far I have only seen properties added to my user object with this method –

context.idToken['https://example.com/favorite_color'] =
    user.user_metadata.color;

However I do not want the property to be namespaced in that way. I would like it to be named color. The properties I want to add are not concerned with idToken.

The first example works when I look at the response in the webtask extension (I can see the user_metadata field), but it does not manifest in the frontend of my app, only the default fields.

Hi @conner.linzy,

Thanks for reaching out to the Auth0 Community!

First, I have tested the Rule snippet and was able to get it to work. I can confirm the doc example works correctly without issues.

In this case, I recommend you check the user’s profile details to verify if the user.user_metadata.preferences has already been created. If so, you will want to delete the property and retry again.

As an alternative, there is also the option to use the Auth0 Post-Login Action to accomplish the same results. For example:

exports.onExecutePostLogin = async (event, api) => {
  if(!event.user.user_metadata.preferences){
    const preference = { "fontSize" : 12 }
    api.user.setUserMetadata("preferences", preference);
  }
};

Please let me know if you need any clarification or have further questions.

Thank you.

first of all, you should try to avoid using rules and use action instead (why) with the action you can do something like this

exports.onExecutePostLogin = async (event, api) => {
  const namespace = 'https://foo.com';
  const user_metadata = event.user.user_metadata || {}
  api.idToken.setCustomClaim(`${namespace}/user_metadata`,user_metada);
};

if you want to know more about auth0 namespace

daamn me @rueben.tiow wrote the solution at the same time :sweat_smile:

1 Like

Hi @pranshushah!

Thank you for also helping out on this topic! :clap:

Yes, I saw you replying at the same time too :smiley:

I will try this out on monday and get back, thanks!

Ok I think I am missing a step here. I see the user metadata in the Auth0 User Details tab

My problem is when I call the user object from the useAuth0 hook, I do not see the user_metadata prop.

To clarify, my previous definition of “not working” was not being able to access the user_metadata prop from user after calling fron useAuth0

I was able to hack this a bit, got this result by adding subfields to a namespaced field. Doesn’t fully solve the issue but can live with it. I’m going to change the name on the frontend and add to my global store and pull from there.

function addPersistenceAttribute(user, context, callback) {
    const mysql = require('mysql');
  
  const connection = mysql.createConnection({
    host: configuration.host,
    user: configuration.user,
    password: configuration.password,
    database: configuration.database
  });
  
  connection.connect();
  const query = `SELECT user_guid, email_verified, active, user_type, last_online , subscription_level FROM users_v2 WHERE email = "${user.email}"`;
  
  connection.query(query, [ user.email ], function(err, results) {
    if (err || results.length === 0) return callback(err || null);

    const dbUser = results[0];
    
    user.user_metadata = user.user_metadata || {};
    user.user_metadata.user_guid = user.user_metadata.user_guid || dbUser.user_guid.toString();
    user.user_metadata.email_verified = user.user_metadata.email_verified || dbUser.email_verified;
    user.user_metadata.active = user.user_metadata.active || dbUser.active;
    user.user_metadata.user_type = user.user_metadata.user_type || dbUser.user_type;
    user.user_metadata.last_online = user.user_metadata.last_online || dbUser.last_online;
    user.user_metadata.subscription_level = user.user_metadata.subscription_level || dbUser.subscription_level;

  context.idToken['https://example.com/user_metadata'] = { ...user.user_metadata };

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

Please do not close the issue! I’d like to know what I am doing wrong.

Hi @conner.linzy,

Thank you for your response.

Having looked closely at your screenshots, it appears that your Rule is updating the user’s user_metadata and appending them as custom claims correctly. Everything seems fine.

Could you please clarify the issues you are experiencing now?

Thanks.

Sure, I dont want to use the namespaced claim. When I access the user_metadata from the Auth0 hook on the frontend I currently need to access it like this:

user['https://example.com/user_metadata'].user_guid

I would prefer to do something like this

user.user_metadata.user_guid

I’m trying to understand why the first example in this thread cannot do that, and why I must use this namespaced field (context.idToken[...). It looks messy, sucks to type, and I will probably have to explain it to my teammates in the future because it is a bit weird.

1 Like

Hi @conner.linzy,

Thank you for your response.

Unfortunately, this is not possible with the useAuth0 hook’s getIdTokenClaims method because it is used to get the claims from the ID Token. In this scenario, the recommendation of appending them to a namespaced claim is the only way to get the user’s user_metadata in the ID token.

As an alternative, you could consider using the Management API get a user endpoint in conjunction with the Post-Login action mentioned here. This way, you can get the user_metadata calling user.user_metadata.user_guid instead of calling the user_metadata as a custom namespaced claim.

Hoped this helps!

Please let me know if you need further clarification or have any questions.

Thank you.

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