OK, I think I figured it out.
This conversation comes up in Google, when you look for how to access user permissions in the req.user object, so Iāll document what I learned here:
You need to create an API (not use the default Auth0 Management API) and create your own set of permission types. In that API, you need to turn on RBAC, and turn on āadd permissions to the access tokenā.
In the express code, following the example, you need to change the the /login code to:
// Perform the login, after login Auth0 will redirect to callback
router.get('/login', passport.authenticate('auth0', {
scope: 'openid email profile',
audience: '<your audience>'
}), function (req, res) {
res.redirect('/');
});
Then you need to look at where the Auth0Strategy is created, and add code to the callback function:
var jsonwebtoken = require('jsonwebtoken');
var Auth0Strategy = require('passport-auth0');
var strategy = new Auth0Strategy(
{
domain: ...
clientID: ...
clientSecret: ...
callbackURL: ...
},
function (accessToken, refreshToken, extraParams, profile, done) {
// accessToken is the token to call Auth0 API (not needed in the most cases)
// extraParams.id_token has the JSON Web Token
// profile has all the information from the user
// decode the access token (does not verify)
var decoded = jsonwebtoken.decode(accessToken);
profile.permissions = decoded.permissions;
console.log(decoded,profile);
// console.log("auth0 strategy callback",...arguments);
return done(null, profile);
}
);
passport.use(strategy);
This copies the permission information into req.user, so that req.user.permissions now has [ āscope:firstā, āscope:secondā ] etc.
Further, if you app has a machine-to-machine connection, you need to:
-
Create a new Machine-to-Machine application
-
Link it to the new API
-
Create the middleware in your app:
const checkJwt = jwt({
// Dynamically provide a signing key
// based on the kid in the header and
// the signing keys provided by the JWKS endpoint.
secret: jwksRsa.expressJwtSecret({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 5,
jwksUri: <your uri>
}),
// Validate the audience and the issuer.
audience: <your API audience uri>,
issuer: <your auth0.com url>,
algorithms: ['RS256']
});
If you include the checkJwt middleware in your path, then req.user will contain req.user.scopes, which has the permissions youāve given to that particular machine-to-machine secret.
To check permissions, you can use middleware code like this:
const default_permissions = [ 'view: public' ];
function checkPermissionJson(scope_required) {
return function(req,res,next)
{
var user = req.user || {};
var scopes = default_permissions.concat(req.user.permissions || req.user.scopes || []);
if(scopes.includes(scope_required)) return next();
return res.status(400).json({error:"Insufficient privileges. Need "+scope_required+"; have "+scopes.join(',')})
}
}
The only thing Iāve not figured out yet is how to run both authentication checks on the same endpoint; for the moment Iāve got M2M endpoints on paths like ā/api/readā and I just use the default passport checks on ā/json/readā but this feels awkward to me.