How to add user permissions to ID token

Hey community. From our single-page application, we want to know the current user’s permission so we can control access to certain sections or buttons of our app.

We’re using organizations. As you’re probably aware, permissions are assigned to roles. Users, in my understanding, can be assigned to roles within the context of organizations and can also be assigned to roles directly (outside the context of organizations). Because of this, we essentially need the union of permissions from (1) all the roles the user is assigned to within the organization the user is currently logged into as well as (2) the permissions from all roles that the user is assigned to directly (outside the context of organizations). This concept of unioning permissions from roles is basically what’s described in the RBAC doc.

I see no good way to do this. A solution I can come up with is to take the following steps within an post-login action:

  • Call management.organizations.getMemberRoles to get all the groups the user is assigned to within the organization the user is logged into.
  • Call management.getPermissionsInRole for each of the roles retrieved in the last step.
  • Call management.getUserPermissions to get all the permissions related to the roles the user is assigned to outside the context of organizations. I assume that’s what this method is doing anyway. The docs are sparse.
  • Merge all the permissions retrieved in the last two steps and add the result to a custom claim on the ID token.

This is obviously very expensive and not feasible.

Another potential solution in our case would be to just copy over the scopes or permissions (if we use the Add Permissions in the Access Token feature) from the access token to the ID token, but I don’t see any way to reference the access token scopes or permissions through actions or rules.

How are we supposed to accomplish this? If we’re not supposed to accomplish this for some security reason, can we get an explanation? This seems like it would be a very common use case.

FWIW, I’ve read the following related posts and I don’t see an answer that actually solves this issue.

The following question received no answers and doesn’t take organizations into consideration.

The following question’s “solution” references a thread that doesn’t take organizations into consideration. Am I misunderstanding?

The following question wanted permissions from not only the org the user is logged into but other orgs as well. In our case, we don’t need (or want) permissions from other orgs, but the comments seem to suggest there’s no good way of solving even our simpler requirements.

The following question has an answer that provides guidance on how to add a user’s permissions to the ID token, but, as far as I’m aware, doesn’t take organizations into consideration.

Thanks in advance!

1 Like

Hey there @aaron.hardy apologize for the delayed response on this one!

The joining of permissions is taken care of by RBAC either outside of the context of an organization (multiple direct roles) or within the context of an organization (multiple roles assigned at org level) but not both as you’ve discovered.

What might be an option, is to rely on the permission array added to the Access Token from a login within the context of a Organization while using the management API to get a user’s direct roles and add those in a separate custom claim. You should be able to infer permissions based on the roles. This does however still require a call to the Management API:

This could be a good candidate for a feedback request as I totally understand where you are coming from.

Let us know what you think!

1 Like

Thanks @tyf.

This is the primary thing I’m trying to avoid. The frontend is supposed to treat the access token as an opaque string and shouldn’t try to decode it:

Respecting this, if I want to access the permissions that are on the access token, I would have to make an extra call to my server API so that the server can decode the access token and return the permissions from it.

Also, if the permissions are in the access token, it means they would be sent to the server on every request to the server when they aren’t actually needed by the server at all. They’re only needed by the SPA.

It seems like it would be much more appropriate and simpler to just add the permissions to the identity token, which is intended for the SPA to use, but I don’t see a feasible way to accomplish this with Auth0.

1 Like

Thanks for following up! Have you considered just using roles and/or even user/app metadata? While not as fine grained, you should be able to make decisions in your SPA based on the roles themselves. You might be able to add both sets of roles to an id token by way of an action - Organization context roles (event.authorization.roles) and direct roles added via the Management API. Again this is not an ideal solution (requires management API) and a bit outside of the current scope so I think a feedback request could be helpful, I’d be curious to see how much traction it would get with others.

I’ve opened this up for discussion to see if anyone else has ideas :bulb:

Thanks @tyf. If we only add roles to the ID token, we would end up needing to map the roles to permissions within the SPA. I hope you can appreciate that having conditionals like:

canCreateTransactions = adminRole | editorRole | supportRole | ...

is less scalable than just having a permission of create:transactions provided to the SPA on the ID token. Within the SPA, we don’t actually care what the user’s roles are; we only care about what they have permission to do.

If we were forced to maintain a mapping between roles to permissions within the SPA, it would end up being identical to the mapping that already exists within Auth0, leading to maintainability issues.

1 Like

I’m running into this exact problem as well.

@aaron.hardy have you managed to get this working with any kind of work around? I’m yet to find a work around that works or is acceptable.

2 Likes

If you just want access to the permissions the user has within the organization, then there is a feasible workaround. The workaround is to put the permissions on the access token, then open up an endpoint on your server that returns the permissions that are on the access token, then make a request to the new endpoint from your SPA to get the permissions. It’s not ideal for multiple reasons. I’m hoping the team at Auth0 can provide a way to just simply put the permissions on the identity token so we can save a request and keep permissions out of the access token since the access token is sent on every request and we only need the permissions in the SPA.

2 Likes

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