Step 4

We want to protect all the routes related to users so only an admin can access them. A naive approach would be to copy and paste the following snippet for each and every route handler:

  const { authorization } = req.headers;
  const [_, token] = authorization.trim().split(" ");
  const valid = await verifyToken(token);
  const user = decodeToken(token);
  if (!valid || user.role !== "ADMIN") {
    return res.status(403).json({
      message:
        "You are not authorized to access this resource.",
    });
  }

A more elegant solution is to use an Express middleware function! According to its documentation:

Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application's request-response cycle. The next middleware function is commonly denoted by a variable named next.

Middleware functions can perform the following tasks:

  • Execute any code.
  • Make changes to the request and the response objects.
  • End the request-response cycle.
  • Call the next middleware function in the stack.

Add the following to the top of the server/routes/users.js before handling any route requests:

const checkAdmin = async (req, res, next) => {
  const { authorization } = req.headers;
  const [_, token] = authorization.trim().split(" ");
  const valid = await verifyToken(token);
  const user = decodeToken(token);
  if (!valid || user.role !== "ADMIN") {
    return res.status(403).json({
      message:
        "You are not authorized to access this resource.",
    });
  }
  next();
};

Then update the route handlers as follows:

- router.get("/api/users", async (req, res) => {
+ router.get("/api/users", checkAdmin, async (req, res) => {
    // Remove the logic for authorization!
    // No change is made to the rest of this route handler!
  });

- router.get("/api/users/:id", async (req, res) => {
+ router.get("/api/users/:id", checkAdmin, async (req, res) => {
    // No change is made to the body!
  });

- router.post("/api/users", async (req, res) => {
+ router.post("/api/users", checkAdmin, async (req, res) => {
    // No change is made to the body!
  });

- router.delete("/api/users/:id", async (req, res) => {
+ router.delete("/api/users/:id", checkAdmin, async (req, res) => {
    // No change is made to the body!
  });

- router.put("/api/users/:id", async (req, res) => {
+ router.put("/api/users/:id", checkAdmin, async (req, res) => {
    // No change is made to the body!
  });

Save the changes. Then, using Postman, send a request to post to /api/users and enclose the authorization token of a regular client (rather than an admin).

Notice the server responded with 403: Access forbidden!

Repeat the same process and this time enclose an admin token!