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.)
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
Routing middleware only accessible by
admin
: