I have followed the boilerplate documentations for configuring a Vue SPA and also configuring the associated backend via Express using the provided middleware handlers exposed via the ‘express-oauth2-jwt-bearer’ package.
All of this works great!
However, I did run into one issue which I have found some prior topics that kinda hit upon the subject, but I wanted to re-post to try and get another response.
Long story short:
If you have an Express route that has for example the auth
and the requiredScopes
middleware handlers configured… I want to verify the incoming JWT but also then make sure the user has specific assigned permissions…
e.g:
import { Request, Response, NextFunction } from 'express'
import { auth, requiredScopes } from 'express-oauth2-jwt-bearer'
router.get(
'/private-scoped',
auth,
requiredScopes(['read:users', 'write:users']),
(_req: Request, res: Response) => {
res.json({
message: 'Hello from a private SCOPED endpoint!.',
})
},
)
When the middleware hits the requiredScopes
, I was looking at the stack trace , it will check that the scope
property on token payload has the permissions I have passed into the requiredScopes
.
Long story short: How do I make the permissions I have assigned directly to the user via the Auth0 web interface get included within the scope
of the token payload?
I was able to solve this by enabling on my Auth0 custom API identifier settings the “Enable RBAC” + “Add Permissions to Access Token”.
This then adds the “permissions” property with the array of permissions that the user has.
I then wrote my own middleware to check the “permissions”. This works great, but I just want to make sure I’m not missing something. I wanted to follow your “best practices” per your knowledge base / tutorials.
Here is my implementation of a requiredPermissions
middleware
import { Request, Response, NextFunction } from 'express'
export const requiredPermissions =
(permission: string | string[]) =>
(req: Request, res: Response, next: NextFunction) => {
const userPermissions = req.auth.payload.permissions as string[]
if (!permission || !userPermissions) {
return res.sendStatus(401)
}
if (typeof permission === 'string') {
return userPermissions.includes(permission) ? next() : res.sendStatus(401)
}
if (Array.isArray(permission)) {
return permission.every(p => userPermissions.includes(p))
? next()
: res.sendStatus(401)
}
}