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)
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?
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.
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:
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
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 ?
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 You would be setting those roles directly via the Management API as I mentioned previously.