Role set on first login, but deleted on subsequent login

Hello good people of Auth0.I can’t help but feel this should be easier than it is… so maybe you can help unfuddle me. I’m setting a role on first login, based off of a query param using context.request.query.role like so with the following rule. But it’s un-setting the role in the metadata on subsequent logins. (Role itself is never set, so seems like I’m faking roles with this metadata array that everyone else seems to be doing too)

function (user, context, callback) {
		const NAMESPACE = "http://mynamespace.com";
    const count = context.stats && context.stats.loginsCount ? context.stats.loginsCount : 0;
    if (count > 1) {
        return callback(null, user, context);
    }

    const ManagementClient = require('auth0@2.27.0').ManagementClient;
    const management = new ManagementClient({
      token: auth0.accessToken,
      domain: auth0.domain
    });
    let roles = [context.request.query.role];
    const params =  { id : user.user_id};
    const data = { "roles" : roles};
  
  
   // resorting to assigning everything -
    context.idToken[`${NAMESPACE}/roles`] = roles;
    context.accessToken[`${NAMESPACE}/roles`] = roles;
    context.authorization.roles = roles;

    management.users.assignRoles(params, data, function (err, user) {
    if (err) {
        // Handle error.
        console.log(err);
     }
    callback(null, user, context);
    });
    
}

I would like that role to be set against that user… and it does appear in the session for that user on the first login.
When logging in again on route that doesn’t provide the query param, the roles array then disappears. I thought this rule would only set it on the first login, then it would persist?

How do I make it so a role is assigned on first login, and it stays assigned?

All help appreciated.

Hey there @colinriddell welcome to the community!

Can you clarify what you mean by the fact that it does appear in the session for the user?

I’m assuming that when you say the role isn’t set, following login with the query param, you don’t get the role with this endpoint?

Let us know!

Hey @tyf - thanks very much for your response.

So yeah. When logging in and setting the role with the query param as above, I want the role to remain in the app_metadata, no matter what happens.
Though for some reason . . (and presumably down to my logic in the rule ?) when logging in without the query then the metadata disappears. Does that make sense @tyf ? Not sure what I’m doing wrong. All help welcome.

Can I ask this question differently…

How do I assign a role on signup/register, and have it stick with that user?

Thanks

Hey @colinriddell no problem, happy to help!

It depends on whether you want to assign roles in app_metadata OR in authorization core. The latter is a bit more complicated/expensive in that it requires use of the Management API directly.

If you just want to add roles to app_metadata, which is a totally valid approach, you might want to switch to Actions and add the roles in to app_metadata in a Post Login Action similar to:

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

let roles = event.request.roles;
 
 //add roles to app_metadata - Leaving out any sort of counting logic
  api.user.setAppMetadata('roles', roles);

};

And then add them to a token(s) in another Post Login Action similar to:

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

const namespace = 'https://myapp.example.com'

  //add app_metadata roles to token(s)
  api.idToken.setCustomClaim(`${namespace}/app_metadata_roles`, event.user.app_metadata.roles);
  api.accessToken.setCustomClaim(`${namespace}/app_metadata_roles`, event.user.app_metadata.roles);
  
};

You’ll just want to make sure you attach these to a flow in the right order. Please also note that I haven’t tested this personally, so you’ll want to be sure and test in your environment :cowboy_hat_face:

Hope this helps!

This lab on enriching user profiles may be useful as well:

Hey @tyf - thanks very much for this.

In the time between posts I managed to get what I wanted to work. Here’s my update rule:

function (user, context, callback) {
    const NAMESPACE = "http://mydomain.com";
    const count = context.stats && context.stats.loginsCount ? context.stats.loginsCount : 0;
  
    if (count > 1) {
        // for every login after the first, set the roles into the token from the previously set metadata
        context.idToken[`${NAMESPACE}/roles`] = user.roles;
        context.accessToken[`${NAMESPACE}/roles`] = user.roles;
        context.authorization.roles = user.roles;
        return callback(null, user, context);
    }
    // everything onwards is first login only:

    const ManagementClient = require('auth0@2.27.0').ManagementClient;
    const management = new ManagementClient({
      token: auth0.accessToken,
      domain: auth0.domain
    });
    let roles = [context.request.query.role];
    const params =  { id : user.user_id};
    const data = { "roles" : roles};
  
     // for the first login set the roles from the assigned login role (from the query string)
    context.idToken[`${NAMESPACE}/roles`] = roles;
    context.accessToken[`${NAMESPACE}/roles`] = roles;
    context.authorization.roles = roles;

    // is this even needed now? I'm not sure it's even working!
    management.users.assignRoles(params, data, function (err, user) {
    if (err) {
        // Handle error.
        console.log(err);
     }
    callback(null, user, context);
    });
  
  
  user.app_metadata = user.app_metadata || {};
  // update the app_metadata that will be part of the response
  user.app_metadata.roles = user.app_metadata.roles || [];
  user.app_metadata.roles.push(roles[0]);

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

So I managed to set the roles into metadata for the first login. And then for subsiquent logins read the roles from that metadata and populate it into the session through the token. Does that look legit to you @tyf ?

Thanks again.
Colin

Hey @colinriddell thanks for following up and good to know!

Your approach looks good to me! If you’re just using the app_metadata then you can skip the ManagementClient bit :slight_smile: You would be setting those roles directly via the Management API as I mentioned previously.

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