Auth0 Home Blog Docs

Permissions: claim or scopes

I am a little confused on best practices in dealing with API permissions. I understand that in the API within Auth0, I can configure it to always attach the permissions claim to the access token. I am confused because I was under the understanding that the spec defines the scopes claim as the place to define a users permissions.

My objective is to have the permissions always included in the access token. I would think you ca achieve this with a rule to automatically add them (although it looks like 'permission’s is not an attribute on the user object). But I’m confused why Auth0 defaults/automates this as a claim rather than adding to scopes?

1 Like

The default Auth0 behavior, of adding permissions as a claim instead of within scopes is contrary to this guide: https://auth0.com/docs/architecture-scenarios/spa-api/part-3

“ the API needs to check the scopes of the decoded JWT. This claim is part of the payload and it is a space-separated list of strings.”

My objective is to have the permissions always included in the access token.

Just a quick answer/solution to this: in your defined API under Dashboard > APIs > [Your API], enable RBAC and check the checkboxes there. Then you have the permissions of the user in the access token.

(You don’t have to ask for them in the authorize request, they’ll always be in there - all permissions of the user. That’s a bit of a difference compared to scopes. Scopes are more for delegation scenarios. Permissions are mostly used in all-first-party scenarios, where client and backend/API are both first-party)

I recall I had answered a few similar/elated posting around permissions, scopes, claims before:
https://community.auth0.com/search?q=permissions%20user%3Amathiasconradt

Regarding the docs link you references in your second post: I think this docs page is older than our release of the RBAC Core features, therefore probably not mentioning it, or still referring to scopes.

@mathiasconradt thanks.

Yes, I know there is the automated way to add permissions to the access token. My question is more about “why” is this added a a custom permissions “claim” and not added to the scopes?

The reason I ask is section 5.4 in the OIDC spec (https://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims) says “The scopes associated with Access Tokens determine what resources will be available when they are used to access OAuth 2.0 protected endpoints.”

As-such, when a API wants to control access, it should rely on the scopes claim according to the standards.In doing it the automated Auth0 way, as you suggested, it technically is not in-line with the standards. Or am I reading the spec wrong?

Sorry, just a quick reply as it’s already late. There’s an interesting blog post around scopes.

Hey @mathiasconradt, thanks for the reply and the link to the blog. My biggest takeaway from the blog really boiled down to:

scopes always limit what an app can do on behalf of a user; they are not meant to grant the application permissions outside of the privileges the delegated user already possesses

and

More precisely, the essence of the problem lies the conviction that the presence of a scope claim in an access token invests the bearer with its corresponding permission, and that a resource (API, etc) being invoked with such a token can/should grant the corresponding access level without any further check .

In other words, do not rely only on scopes to give users access to resources. Things like the user id and the resources they are trying to access are also just as important. I understand this and agree, you can not rely 100% on scopes, or a users permissions/roles, to decide if the user actually has access to the resource they are trying to interact with.

Unfortunitely I do not see the article touching on when/why to use a custom claim, permissions in Auth0’s case, instead of the scopes claim. Reading this article, further makes me believe that the right place to put those permissions is actually in the scopes claim.

The permissions could’ve been put as well in the scope claim (as it doesn’t really matter what the claim is called) as well, it was a design decision by the product team. Because the use cases are different ones.
Actually, I had the very same question in the very beginning as well, before I received some explanation. I hope I can explain it in a clear way:

Permissions (as opposed to scopes) are usually used in scenarios with first party frontend and backend, where this:

scopes always limit what an app can do on behalf of a user

is usually never needed. The app (client) doesn’t need to work with scopes here, as the backend usually always trusts the frontend (as it’s both first party = from the same vendor). There’s no need for any kind of delegation to the client app, since it’s always a trusted client.
For this very reason Auth0 by the way also have the option to allow to not show the consent screen

because it usually doesn’t make much sense there.

All that needs to be done is checking user permissions. No delegation of user permissions to a client is needed. The latter though is what OAuth2 is using the scopes for though, but that’s not really needed here.

Hey @mathiasconradt, I hate to come back to this topic, but I am struggling coming to peace with not putting the permissions inside the scopes claim. As an example, when I create an Auth0 Management API token, the JWT that is given to me has the permissions contained within Scopes. Why does Auth0 add them to the scopes when you recommend adding them to permissions.

On the same topic, if I choose to add them to the scopes myself, can you point me to some documentation that will tell me how to go about doing that?

Thanks.

Hi @mcardle.liam,

Disable this feature in the API settings as you don’t need them.

Then add and enable this rule:

function (user, context, callback) {

  var ManagementClient = require('auth0@2.17.0').ManagementClient;
  var management = new ManagementClient({
    token: auth0.accessToken,
    domain: auth0.domain
  });

  var params = { id: user.user_id};

  management.getUserPermissions(params, function (err, permissions) {
    
    var permissionNames = [];
    permissions.forEach(function(obj) { permissionNames.push(obj.permission_name); });
    
    if (err) {
      // Handle error.
    }
    context.accessToken.scope = permissionNames;    
    callback(null, user, context);
  });
  
}
1 Like

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