Home  >  Q&A  >  body text

Add multiple roles to protected routes (Node + Express + JWT)

I'm trying to secure some routes using user roles (some routes accept multiple roles). When I list the accepted roles in the route handler, only the first user role listed is allowed access - I need to allow access for all roles listed.

This is the authentication middleware file (auth.js) that decodes the JWT token:

import jwt from "jsonwebtoken";

const auth = (req, res, next) => {
  const token = req.header("x-auth-token");
  if (!token)
    return res
      .status(401)
      .send({ message: "Access denied. No token provided!" });

  try {
    const decoded = jwt.verify(token, "SomethingPrivate");
    req.user = decoded;
    next();
  } catch (ex) {
    res.status(400).send({ message: "Invalid Token." });
  }
};

export const superAdmin = (req, res, next) => {
  const token = req.header("x-auth-token");
  if (!auth && !token)
    return res.status(401).send({ message: "Access denied." });

  const decoded = jwt.verify(token, "SomethingPrivate");
  if (auth && decoded.role === "superAdmin") {
    res.status(200);
    next();
  } else {
    res.status(400).send({ message: "Access denied!" });
  }
};

export const admin = (req, res, next) => {
  const token = req.header("x-auth-token");
  if (!auth && !token)
    return res.status(401).send({ message: "Access denied." });

  const decoded = jwt.verify(token, "SomethingPrivate");
  if (auth && decoded.role === "admin") {
    res.status(200);
    next();
  } else {
    res.status(400).send({ message: "Access denied!" });
  }
};

export const teacher = (req, res, next) => {
  const token = req.header("x-auth-token");
  if (!auth || !token)
    return res.status(401).send({ message: "Access denied." });

  const decoded = jwt.verify(token, "SomethingPrivate");
  if (auth && decoded.role === "teacher") {
    res.status(200);
    next();
  } else {
    res.status(400).send({ message: "Access denied!" });
  }
};

export const student = (req, res, next) => {
  const token = req.header("x-auth-token");
  if (!auth || !token)
    return res.status(401).send({ message: "Access denied." });

  const decoded = jwt.verify(token, "SomethingPrivate");
  if (auth && decoded.role === "student") {
    res.status(200);
    next();
  } else {
    res.status(400).send({ message: "Access denied!" });
  }
};

export const parent = (req, res, next) => {
  const token = req.header("x-auth-token");
  if (!auth) return res.status(401).send({ message: "Access denied." });

  const decoded = jwt.verify(token, "SomethingPrivate");
  if (auth && decoded.role === "parent") {
    res.status(200);
    next();
  } else {
    res.status(400).send({ message: "Access denied!" });
  }
};

This is the router file (userRoute.js):

import express from "express";
import {
  superAdmin,
  admin,
  teacher,
  student,
  parent,
} from "../middleware/auth.js";
const router = express.Router();
import {
  view,
  find,
  me,
  create,
  edit,
  update,
  viewUser,
} from "../controllers/userController.js";

// Routes
router.get("/", [superAdmin, admin], view); //The route I am struggling with at the moment//
router.post("/", find);
router.get("/me", me);
router.post("/create", superAdmin, create);
router.get("/edituser/:userID", edit);
router.post("/edituser/:userID", [], update);
router.get("/viewuser/:userID", viewUser);


export { router as user };

Finally, the data for the JWT payload is inserted when signing on login and stored in the response header:

const token = jwt.sign(
              {
                userID: result[0].userID,
                firstName: result[0].firstName,
                lastName: result[0].lastName,
                email: result[0].email,
                role: result[0].role,
              },

In the userRoute.js file, I tried using a pipe operator between each accepted role for that route, but I can't seem to get the role to be treated as a boolean.

Any help would be greatly appreciated! (This is the backend that will be paired with the React frontend in the near future.)

P粉476547076P粉476547076245 days ago259

reply all(1)I'll reply

  • P粉369196603

    P粉3691966032024-02-18 10:42:11

    Arrays of middleware functions always work like routes specified in order. This means that if you call res.send() in one of the middleware functions, all the next functions in the array have not been used yet.

    I would suggest this, for example:

    Middleware for access routing by parents, students, and administrators

    export const parent = (req, res, next) => {
      const token = req.header("x-auth-token");
      if (!auth) return res.status(401).send({ message: "Access denied." });
    
      const decoded = jwt.verify(token, "SomethingPrivate");
      if (auth && ["parent", "student", "admin"].includes(decoded.role)) {
        res.status(200);
      } else {
        res.status(400).send({ message: "Access denied!" });
      }
    };

    Routing middleware only accessible by admin:

    export const parent = (req, res, next) => {
      const token = req.header("x-auth-token");
      if (!auth) return res.status(401).send({ message: "Access denied." });
    
      const decoded = jwt.verify(token, "SomethingPrivate");
      if (auth && ["admin"].includes(decoded.role))) {
        res.status(200);
      } else {
        res.status(400).send({ message: "Access denied!" });
      }
    };

    reply
    0
  • Cancelreply