The first thing we should define is who can use the users
resource. These are the scenarios that we’ll
need to handle:
· Public for creating users (registration process). We will not use JWT for this scenario.
· Private for the logged-in user and for admins to update that user.
· Private for admin only for removing user accounts.
Having identified these scenarios, we will first require a
middleware that always validates the user if they are using a valid JWT. The middleware
in /common/middlewares/auth.validation.middleware.js
can be as
simple as:
exports.validJWTNeeded =
(req, res, next) => {
if (req.headers[
'authorization']) {
try {
let authorization = req.headers[
'authorization'].split(
' ');
if (authorization[
0] !==
'Bearer') {
return res.status(
401).send();
}
else {
req.jwt = jwt.verify(authorization[
1], secret);
return next();
}
}
catch (err) {
return res.status(
403).send();
}
}
else {
return res.status(
401).send();
}
};
We will use HTTP error codes for handling request errors:
· HTTP 401 for an invalid request
· HTTP 403 for a valid request with an invalid token, or valid token with invalid permissions
We can use the bitwise AND operator (bitmasking) to control the permissions. If we set each required permission as a power of 2, we can treat each bit of the 32bit integer as a single permission. An admin can then have all permissions by setting their permission value to 2147483647. That user could then have access to any route. As another example, a user whose permission value was set to 7 would have permissions to the roles marked with bits for values 1, 2, and 4 (two to the power of 0, 1, and 2).
The middleware for that would look like this:
exports.minimumPermissionLevelRequired =
(required_permission_level) => {
return
(req, res, next) => {
let user_permission_level =
parseInt(req.jwt.permission_level);
let user_id = req.jwt.user_id;
if (user_permission_level & required_permission_level) {
return next();
}
else {
return res.status(
403).send();
}
};
};
The middleware is generic. If the user permission level and the required permission level coincide in at least one bit, the result will be greater than zero and we can let the action proceed, otherwise the HTTP code 403 will be returned.
Now, we need to add the authentication middleware to the user’s
module routes in /users/routes.config.js
:
app.post(
'/users', [
UsersController.insert
]);
app.get(
'/users', [
ValidationMiddleware.validJWTNeeded,
PermissionMiddleware.minimumPermissionLevelRequired(PAID),
UsersController.list
]);
app.get(
'/users/:userId', [
ValidationMiddleware.validJWTNeeded,
PermissionMiddleware.minimumPermissionLevelRequired(FREE),
PermissionMiddleware.onlySameUserOrAdminCanDoThisAction,
UsersController.getById
]);
app.patch(
'/users/:userId', [
ValidationMiddleware.validJWTNeeded,
PermissionMiddleware.minimumPermissionLevelRequired(FREE),
PermissionMiddleware.onlySameUserOrAdminCanDoThisAction,
UsersController.patchById
]);
app.delete(
'/users/:userId', [
ValidationMiddleware.validJWTNeeded,
PermissionMiddleware.minimumPermissionLevelRequired(ADMIN),
UsersController.removeById
]);
This concludes the basic development on our REST API. All that remains to be done is to test it all out.