Insufficient Scope but my token contains required permissions

Hi all, my first post here. I could not find anything relating to the issue that I am having and I’m hoping that someone can help me in order to save me some time. I am also new to using Auth0 and have started building an application that uses Auth0.

As the title suggests, I have a Node JS API which has a GET /users endpoint. This endpoint checks for a JWT and it also checks if the JWT is bearing the required scopes. For some reason when I call the GET endpoint, I get a response Insufficient Scope.

My API endpoint code looks like this:

// Scope required to get all users
const getUsersScopes = jwtAuthz(['read:users']);

const authConfig = {
    audience: "https://api.myapp.com/",
    domain: "myapp.auth0.com"
};

const checkJwt = jwt({
    secret: jwksRsa.expressJwtSecret({
        cache: true,
        rateLimit: true,
        jwksRequestsPerMinute: 5,
        jwksUri: `https://${authConfig.domain}/.well-known/jwks.json`,
    }),
        
    audience: authConfig.audience,
    issuer: `https://${authConfig.domain}/`,
    algorithms: ['RS256']
});

app.route('/users')
    .get(checkJwt, getUsersScopes, (req: Request, res: Response, next: NextFunction) => {
        next();
    }, this.userController.getUsers);
}

Then I have an Angular app which sends my token to the API, and I can see that the token that is sent to the API contains a permissions property and it’s an array of all the permissions that my user has. It looks like so:

{
  "iss": "https://myapp.auth0.com/",
  "sub": "...",
  "aud": [
    "https://api.myapp.com/",
    "https://myapp.auth0.com/userinfo"
  ],
  "iat": ...,
  "exp": ...,
  "azp": "...",
  "scope": "openid profile email",
  "permissions": [
    "read:user",
    "read:users",
    "remove:user",
    "update:user",
    "write:user"
  ]
}

My question is, why does my Node JS API respond with “Insufficient Scope” when my token contains the required scope read:users?

I can call the endpoint perfectly fine when I remove the getUsersScopes from the .get() ednpoint like so:

app.route('/users')
    .get(checkJwt, (req: Request, res: Response, next: NextFunction) => {
        next();
    }, this.userController.getUsers);
}

Am I missing something obvious? Any advice would be greatly appreciated.

Thanks in advance,
Morné

1 Like

Alright to answer my own question, well part of it, I found out that you can change the scope the permissions are checked against, as seen here: https://github.com/auth0/express-jwt-authz#options

So I added options to the jwtAuthz like so:

var options = {
    customScopeKey: 'permissions'
};
const getUsersScopes = jwtAuthz(['read:users'], options);

This made it check for the permissions in the permissions array found in the JWT, instead of the scope field in the JWT token.

I hope this helps other noobs like me out there :yum:

Happy coding!
Morné

5 Likes

Glad you were able to figure it out yourself! Really appreciate that you also shared it with the rest of community!

Why is this buried so deep in the docs? I wanted to change from Scopes to Roles/Permissions and been looking for two days for the solution. Docs really need to address Scope and Permission distinction.

Thanks for sharing that feedback @clifford.eby! I’ll make sure to relay that to our docs team.

Additionally, I had an older version of jwtAuthz. It had to be npm update d. If you see
express deprecated res.send(status, body): Use res.status(status).send(body) instead node_modules\express-jwt-authz\lib\index.js:2:14 as a message in the server console , you need to update.

1 Like

Thanks for reporting that!

Dealing with this has been the worst development experience of my career.

Thank you! Foolishly I’d been following one of the “worked examples” in the docs which didn’t work straight out of the box…

Have a great day.

In my case, I needed to provide “customScopeKey” and “customUserKey” as the default key is “user”, but in the “expressjwt 6.x.x” it was changed to “auth”. (GitHub - auth0/express-jwt: connect/express middleware that validates a JsonWebToken (JWT) and set the req.user with the attributes)

jwtAuthz(['read:company'], { customScopeKey: 'permissions', customUserKey: 'auth' })
1 Like

Thank you very much for pointing that out!

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