Auth0 with multiple Roles setup

I have successfully setup basic Auth with Auth0 and RW. I want to add roles to the sign up process. I added a Role to a user in Auth0’s configuration panel called SuperAdmin, eventually I want to assign admin and other roles via the SuperAdmin panel in my app.

I have followed these two sections

When I run the Rules test in Auth0 I get the following object back

{
  "https://memgrok.com/app_metadata": {
    "authorization": {
      "roles": [
        "SuperAdmin"
      ]
    }
  },
  "https://memgrok.com/user_metadata": {}
}

But when I use console.log('hasRole', hasRole('SuperAdmin'))
I get false

and I have added the following to my auth.js file

const NAMESPACE = 'https://memgrok.com'

 const currentUserWithRoles = async (decoded) => {
   const currentUser = await userByUserId(decoded.sub)
   return {
     ...currentUser,
     roles: parseJWT({ decoded: decoded, namespace: NAMESPACE }).roles,
   }
 }

export const getCurrentUser = async (decoded, { type, token }) => {
  try {
    requireAccessToken(decoded, { type, token })
    return currentUserWithRoles(decoded)
  } catch (error) {
    return decoded
  }
}

I am not clear on how to assign Roles from within my app, not just in Auth0’s admin panel. And how to retrieve the roles that have been assigned after a user has signed in.

Update:

The second rule from the docs when I try and run it in tests it returns

Cannot read property 'groups' of undefined

from this Rule

function (user, context, callback) {
  var namespace = 'https://memgrok.com/';

  // adds to idToken, i.e. userMetadata in RedwoodJS
  context.idToken[namespace + 'app_metadata'] = {};
  context.idToken[namespace + 'app_metadata'].authorization = {
    groups: user.app_metadata.groups,
    roles: user.app_metadata.roles,
    permissions: user.app_metadata.permissions
  };

  context.idToken[namespace + 'user_metadata'] = {};

  // accessToken, i.e. the decoded JWT in RedwoodJS
  context.accessToken[namespace + 'app_metadata'] = {};
  context.accessToken[namespace + 'app_metadata'].authorization = {
    groups: user.app_metadata.groups,
    roles: user.app_metadata.roles,
    permissions: user.app_metadata.permissions
  };

   context.accessToken[namespace + 'user_metadata'] = {};

  return callback(null, user, context);
}

Update 2

I did notice in the jwt claims local storage I get the following

https://memgrok.com/app_metadata: {authorization: {roles: ["SuperAdmin"]}}
https://memgrok.com/user_metadata: {}

So not exactly sure here

So when I check the userMetaData

I get the following

{ "https://memgrok.com/app_metadata": { "authorization": { "roles": [ "SuperAdmin" ] } }, "https://memgrok.com/user_metadata": {}, "nickname": "anders", "name": "anders@email.org", "picture": "https://s.gravatar.com/avatar/fd?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fan.png", "updated_at": "2021-12-17T02:02:27.298Z", "email": "anders@kitson.org", "email_verified": false, "sub": "auth0|6fdf" }

I noticed in the following sections

userByUserId does not exist as a function in auth.ts

const NAMESPACE = 'https://memgrok.com'

const currentUserWithRoles = async (decoded) => {
  const currentUser = await userByUserId(decoded.sub)
  return {
    ...currentUser,
    roles: parseJWT({ decoded: decoded, namespace: NAMESPACE }).roles,
  }
}

and requireAccessToken does not exist either

export const getCurrentUser = async (decoded, { type, token }) => {
  try {
    requireAccessToken(decoded, { type, token })
    return currentUserWithRoles(decoded)
  } catch (error) {
    return decoded
  }
}

I copied these from the Auth0 docs, so not sure where they are supposed to come from

UPDATE

Got it working turns out I needed to just amend the current getCurrentUser with the parse jwt role check

const NAMESPACE = 'https://memgrok.com'

export const getCurrentUser = async (
  decoded,
  { token, type },
  { event, context }
) => {
  if (!decoded) {
    return null
  }

  const roles = parseJWT({ decoded: decoded, namespace: NAMESPACE }).roles

  if (roles) {
    return { ...decoded, roles }
  }

  return { ...decoded }
}

@anderskitson Thank you for posting this β€” both the question and answer! It’s really helpful for others as it adds to a growing, searchable knowledge base.

Looping in @dthyresson just to make sure he sees this.

1 Like