Why is roles claim missing after signup?

As a part of the user signup I’ve added a rule to set the user role based on a signup query parameter.
When I inspect the users profile after signing up, the role is applied.
My problem is that the token I receive back from the signup process, does not contain the newly assigned role of the user. I explicitly to try set the roles claim of the token to a known value, but when I inspect the token, the roles claim is missing. Somehow it’s being overwritten by something. If the user logs out and back in again, the token has the roles claim set as expected.

This is the rule I run after the rule where I apply the role:

function (user, context, callback) {
  
  const namespace = 'mynamespace';
  const assignedRoles = context.authorization || {}.roles;
  user.user_metadata = user.user_metadata || {};
  user.app_metadata = user.app_metadata || {};
  let accessTokenClaims = context.accessToken || {};
  
  if (user.app_metadata.mode === "SuperCoolUser") {
    console.log("I am supercool user");
    accessTokenClaims[`${namespace}/roles`] = user.app_metadata.mode;
  }
  
  accessTokenClaims[`${namespace}/userId`] = user.user_id;
  accessTokenClaims[`${namespace}/user`] = user.user_metadata.user;
  accessTokenClaims[`${namespace}/mode`] = user.app_metadata.mode;
  
  context.accessToken = accessTokenClaims;
  return callback(null, user, context);
}

How can I work around this?

Hi @erlend,

Can you confirm that there isn’t another rule that is writing over the accessToken object?

Hi @dan.woda, here is the summary of rules and flows.

1 (rule).

function(user, context, callback) {
    Promise.resolve()
      .then(() => {
        var response = {};
        response.user = user;
        user.app_metadata.mode = context.request.query.mode;
        var role = context.request.query.mode;
        auth0.users.updateAppMetadata(user.user_id, user.app_metadata);

        // only set the role from the query param first time.
        if (role === 'SuperCoolUser') {
          var count = context.stats && context.stats.loginsCount ? context.stats.loginsCount : 0;
          if (count > 1) {
            return callback(null, user, context);
          }
  
          var ManagementClient = require('auth0@2.17.0').ManagementClient;
          var management = new ManagementClient({
            token: auth0.accessToken,
            domain: auth0.domain
          });
  
          // assign the role from the query param to the user.
          management.assignRolestoUser(
              {id: user.user_id}, {"roles": ["role_id"]
            }, 
            (err) => {
                console.log("Failed to assign roles: " + err);
              if (!err) {
                console.log("Successfully assigned roles");
              }
              return callback(err, user, context);
            });
        }
        return callback(null, user, context);
      })
      .then(() => {
        callback(null, user, context);
      })
      .catch(reason => {
        console.log(reason);
        callback(reason);
      });
  }

2 (rule). function (user, context, callback) {
  
  const namespace = 'mynamespace';
  const assignedRoles = context.authorization || {}.roles;
  user.user_metadata = user.user_metadata || {};
  user.app_metadata = user.app_metadata || {};
  let accessTokenClaims = context.accessToken || {};
  
  if (user.app_metadata.mode === "SuperCoolUser") {
    console.log("I am supercool user");
    accessTokenClaims[`${namespace}/roles`] = user.app_metadata.mode;
  }
  
  accessTokenClaims[`${namespace}/userId`] = user.user_id;
  accessTokenClaims[`${namespace}/user`] = user.user_metadata.user;
  accessTokenClaims[`${namespace}/mode`] = user.app_metadata.mode;
  
  context.accessToken = accessTokenClaims;
  return callback(null, user, context);
}

3 (flow).

exports.onExecutePostLogin = async (event, api) => {
  const namespace = 'https://mysupercoolnamespace';
  if (event.authorization) {
    api.idToken.setCustomClaim(`${namespace}/roles`, event.authorization.roles);
    api.accessToken.setCustomClaim(`${namespace}/roles`, event.authorization.roles);
    api.accessToken.setCustomClaim(`${namespace}/userId`, event.user.email);
    api.accessToken.setCustomClaim(`${namespace}/user`, event.user.user_metadata.user);
  }
}

I’m not sure if the login flow is executed before returning the token to the user?
Regards,

Erlend

I think you may be missing the role on first login because the context.authorization object is already created before you have added the role to the user. You will have to manually add the role to the token on first login in addition to adding it via the management API.

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