Scopes vs Permissions confusion

I’m new to Auth0 and getting a bit confused about scopes and permissions and how they relate.

A lot of the documentation implies that scopes are permissions, and that you should create scopes such as “read:messages” and “write:messages”.

But when you create Permissions in the API, and then request an Access Token from the front-end, these appear in a “permissions” claim but not in the list of scopes.

However if you create Permissions through the Authorization Extension, then they do appear as scopes in the Access Token and not as a Permissions claim.

How is this supposed to work and why is there this difference between the Authorization Extension and the way the main one works?

8 Likes

Hi @chrisj2,

here are some related threads on this:

1 Like

Thanks for those links. Reading them has made me even more confused, what is the correct behaviour supposed to be?

If I’m writing an API, do I need to check both the Permissions claim and the Scopes claim to determine permissions, because Auth0 might set them in one or the other depending on configuration?

The documentation is not clear about this, and seems to state that the Scopes claim has the permissions in it, whereas in reality the Permisions claim does.
For example, the sample code on this page:

doesn’t work for me because the permissions are not actually in the Scopes claim?

I’m trying to understand how things are supposed to work and what Auth0’s official position on this is?

6 Likes

Gonna +1 this. I am fighting with the same thing in the documentation right now. There is no clear guidance on what you’re supposed to do here.

I’m also using the ASP.NET Core API Quickstart, and it simply doesn’t work as written. First, it neglects to mention that you need to turn on RBAC and the option to include permissions in the access token. Finally got that done, but the HasScopeHandler class is specifically looking for the scope claim, where these come across as permissions.

What’s the correct path here?

6 Likes

+1 this as well, i am having exactly the same confusion.

3 Likes

+1 from me too. I am also incredibly confused. That first thread provides a solution for the poster’s specific scenario, but doesn’t make clear the distinction between scopes and permissions. The behaviour seems really inconsistent.

3 Likes

I am back into this today trying to figure it out also. I tried to email support and didn’t ever get a clear answer. Trying to get an API that can validate the permissions of a M2M app and a user seems like such a simple requirement for Auth0 to fulfill, but it doesn’t work without major hoops to jump through.

2 Likes

I think the answer is to modify their code to first check for permissions, then move on to checking for the scope like they demonstrate. This seems to be working for me. Whether this is the correct approach, I have no idea since they won’t give a clear answer or update example. I’ll keep messing with this.

public class HasScopeHandler : AuthorizationHandler<HasScopeRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, HasScopeRequirement requirement)
    {
        // First check for permissions, they may show up in addition to or instead of scopes...
        if (context.User.HasClaim(c => c.Type == "permissions" && c.Issuer == requirement.Issuer && c.Value == requirement.Scope))
        {
            context.Succeed(requirement);
            return Task.CompletedTask;
        }

        // This is the Auth0 version, which only checks for scopes instead of permissions.
        // If user does not have the scope claim, get out of here
        if (!context.User.HasClaim(c => c.Type == "scope" && c.Issuer == requirement.Issuer))
            return Task.CompletedTask;

        // Split the scopes string into an array
        var scopes = context.User.FindFirst(c => c.Type == "scope" && c.Issuer == requirement.Issuer).Value.Split(' ');

        // Succeed if the scope array contains the required scope
        if (scopes.Any(s => s == requirement.Scope))
            context.Succeed(requirement);

        return Task.CompletedTask;
    }
}
3 Likes

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

:wave: I would like to share some updates for the core authorization.

We introduced TOKEN_DIALECT which helps to get the scopes in the Access Token based on the permissions assigned to the user either directly or through roles.

When the RBAC feature is enabled along with token dialect for an API, the permissions which are allowed for the user and requested by the application will be inserted in the scope attribute of the issued Access Token.

An app may request one or more permissions for a specific API. E.g let’s say I have an API with the API identifier named https://myblogapi and the associated permissions read:posts , update:posts and delete:posts.

My blog application only needs read:posts and update:posts so it asks for them in the scope attribute.

https://myblog.us.auth0.com/authorize?scope=openid read:posts update:posts&audience=https://myblogapi&client_id=1234567&response_type=code&redirect_uri=https://myblog.com/callbacki&state=abc

Let’s say Alice has an admin role that allows her to have all of the above permissions. When Alice clicks on the login button, my blog redirects Alice’s browser to the Universal Login with the above URL.

When Alice logs in, as she has all of the requested permissions, the Access Token will have both read:posts and updata:posts permissions in the scope but not the delete:posts.

However let’s say Bob is a regular user who has only the permission to read the posts so he has the read:posts permission, so the same URL above will issue an Access Token with read:posts permission only for him.

7 Likes

Thanks for updating that thread Saltuk!