Converting Rule to Action

How do you convert the legacy rule called “Move user metadata attributes to profile root attributes” into an Action? The only example I could find was this, but it does not set the user profile value.

exports.onExecutePostLogin = async (event, api) => {
api.user.setUserMetadata(“given_name”, “John”);
};

Hey there @bbarnell welcome to the community!

We unfortunately don’t have a pre-existing example of the same functionality in an Action, but I was able to just test this code in my own environment and it seems to be functioning as expected:

const { ManagementClient } = require('auth0');

exports.onExecutePostLogin = async (event, api) => {
  const fieldMapping = {
    family_name: 'family_name',
    given_name: 'given_name',
    name: 'name',
    nickname: 'nickname',
    picture: 'picture'
  };

  if (needMigration(event.user)) {
    const management = new ManagementClient({
        domain: event.secrets.domain,
        clientId: event.secrets.clientID,
        clientSecret: event.secrets.clientSecret,
    });

    try {
      const updatedUser = await management.updateUser(
        { id: event.user.user_id },
        generateUserPayload(event.user)
      );
      updateActionUser(event.user, updatedUser);
    } catch (err) {
      console.error(err);
      throw new Error('Failed to migrate user attributes.');
    }
  }

  function needMigration(user) {
    if (user.user_metadata) {
      for (const key in fieldMapping) {
        if (typeof user.user_metadata[fieldMapping[key]] === 'string') {
          return true;
        }
      }
    }
    return false;
  }

  function generateUserPayload(user) {
    const payload = { user_metadata: {} };
    const userMetadata = user.user_metadata;

    for (const key in fieldMapping) {
      generateUserPayloadField(userMetadata, payload, key, fieldMapping[key]);
    }

    return payload;
  }

  function updateActionUser(user, updatedUser) {
    for (const key in fieldMapping) {
      if (typeof user.user_metadata[fieldMapping[key]] === 'string') {
        user[key] = updatedUser[key];
        delete user.user_metadata[fieldMapping[key]];
      }
    }
  }

  function generateUserPayloadField(userMetadata, payload, rootField, metadataField) {
    if (typeof userMetadata[metadataField] === 'string') {
      payload[rootField] = userMetadata[metadataField];
      payload.user_metadata[metadataField] = null;
    }
  }
};

I attempted to mirror the Rule code as closely as possible - I will note that it might be worth looking into caching the Management API access token as well:

Hope this helps!

I was unable to get this code to work, so I tried to simplify it and now I get this error message when I run the script in the editor window. What am I doing wrong?

unauthorized_client: {“error”:“unauthorized_client”,“error_description”:“Grant type ‘client_credentials’ not allowed for the client.”,“error_uri”:“Application Grant Types”}
at /data/layers/

Here is my test code:

const { ManagementClient } = require(‘auth0’);

exports.onExecutePostLogin = async (event, api) => {

  const management = new ManagementClient({
     domain: event.secrets.domain,
     clientId: event.secrets.clientID,
     clientSecret: event.secrets.clientSecret,
  });

  const user = event.user;
  const user_id = user.user_id;

  user.user_metadata.given_name = "John Doe";
  const given_name = user.user_metadata.given_name;

  console.log("** user_id: " + user_id);
  console.log("** given_name: " + given_name);
  console.log("** user object", user);

  const updateUserData = {given_name: given_name};
  
  try {
     const updatedUser = await management.updateUser(
        { id: user_id },
        updateUserData
     );

     console.log("** Updated user", updatedUser);
     
  } catch (err) {
     console.error(err);
     throw new Error('Failed to migrate user attributes.');
  }

};

This most likely has to do with the application you are using to instantiate the ManagementClient - This should be an M2M app and you should see “Client Credentials” enabled if you go to application settings → advanced settings → grant types.

The application also needs to be authorized by the Management API - You can do this by navigating to applications → APIs → Management API → machine to machine applications.

This is a Mobile Single Page application where I am trying to convert the rule: legacy rule called “Move user metadata attributes to profile root attributes” into an Action before it expires next year and no longer works. What is the best approach for this? I am getting nowhere coding actions.

1 Like

Hey @bbarnell !

The code I shared previously works in my own environment, so it should work in yours. Are you able to go into a bit more detail as to why exactly the code wasn’t working for you? The more details you can share the better.

Please close this ticket. I found a workaround for this issue.

1 Like

Hi there, Im having a similar issue that OP has. We use the rule “Move user metadata attributes to profile root attributes” but as rules are going to be removed, we need to convert what this does into an Action.

I tried to paste in the code you provided @tyf when creating a new Action, but I got the error as seen in attached image.

How would I go about to fix this?
Would this solution increase our API quota someway?

Edit: Follow up question. Is there a better way to solve this? What I need to achieve is that i need to access custom data in app_metadata upon user login as seen in the attached image.

Best regards,
Dick

Okey, I think I solved it by adding this action:

exports.onExecutePostLogin = async (event, api) => {
  const namespace = 'http://somedomain';
  
  if (event.authorization) {
    api.idToken.setCustomClaim(`${namespace}/app_metadata`, event.user.app_metadata);
  }
};

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