What if one forgotten permission check could expose your whole app to unauthorized users?
Why Permission middleware in Express? - Purpose & Use Cases
Start learning this pattern below
Jump into concepts and practice - no test required
Imagine building a web app where you must check user permissions on every page manually. You write repeated code everywhere to see if a user can access a page or perform an action.
This manual checking is tiring and error-prone. You might forget to check permissions in some places, causing security holes. It also makes your code messy and hard to update.
Permission middleware lets you centralize permission checks in one place. It automatically runs before your routes and blocks unauthorized users, keeping your code clean and secure.
if (user.role !== 'admin') { res.status(403).send('Forbidden'); return; } next();
app.use(permissionMiddleware('admin'));You can easily protect routes and actions with reusable, clear permission rules that keep your app safe and maintainable.
Think of a company dashboard where only managers can access employee salary data. Permission middleware ensures only managers see that info without repeating checks everywhere.
Manual permission checks are repetitive and risky.
Middleware centralizes and automates permission control.
This keeps your app secure, clean, and easier to maintain.
Practice
Solution
Step 1: Understand middleware role
Middleware runs before route handlers to control flow or check conditions.Step 2: Identify permission middleware function
Permission middleware specifically checks user rights to allow or deny access.Final Answer:
To check if a user has rights to access a route before running its handler -> Option AQuick Check:
Permission middleware controls access = A [OK]
- Confusing permission middleware with logging middleware
- Thinking it formats response data
- Assuming it handles errors
Solution
Step 1: Check middleware signature
Express middleware must have three parameters: req, res, next.Step 2: Verify correct usage of next()
If permission fails, respond or send error; else call next() to continue.Final Answer:
function checkPermission(req, res, next) { if (!req.user) res.send('No user'); else next(); } -> Option CQuick Check:
Middleware needs (req, res, next) and calls next() [OK]
- Missing next parameter
- Calling next() without parentheses
- Not sending response or calling next() properly
function permitAdmin(req, res, next) {
if (req.user?.role !== 'admin') {
return res.status(403).send('Forbidden');
}
next();
}
app.get('/admin', permitAdmin, (req, res) => {
res.send('Welcome Admin');
});Solution
Step 1: Check user role in middleware
The middleware checks if req.user.role is not 'admin'. Here it is 'guest', so condition is true.Step 2: Middleware response on failed permission
It sends status 403 with 'Forbidden' and does not call next(), so route handler is skipped.Final Answer:
Forbidden -> Option AQuick Check:
Role not admin = 403 Forbidden [OK]
- Assuming route handler runs anyway
- Confusing status codes
- Missing optional chaining on req.user
function checkPermission(req, res, next) {
if (!req.user.permissions.includes('edit')) {
res.status(401).send('Unauthorized');
}
next();
}Solution
Step 1: Analyze flow after sending response
After res.status(401).send(), the code continues and calls next(), allowing next middleware or route to run.Step 2: Fix by adding return to stop execution
Adding 'return' before res.status(401).send() prevents next() from running when unauthorized.Final Answer:
Missing return after sending response, so next() runs anyway -> Option DQuick Check:
Send response must return to stop next() [OK]
- Not returning after sending response
- Using wrong HTTP status code
- Assuming next() should never be called
Solution
Step 1: Understand the requirement
Access allowed if user role matches any role in allowedRoles array.Step 2: Check each option logic
function permitRoles(allowedRoles) { return (req, res, next) => { if (!allowedRoles.includes(req.user.role)) { res.status(403).send('Forbidden'); } next(); }; } uses includes but misses return before res.send(), so next() runs anyway. function permitRoles(allowedRoles) { return (req, res, next) => { if (allowedRoles.indexOf(req.user.role) === -1) { res.status(403).send('Forbidden'); } next(); }; } misses return before res.send(), so next() runs anyway. function permitRoles(allowedRoles) { return (req, res, next) => { if (allowedRoles.some(role => role === req.user.role)) { next(); } else { res.status(403).send('Forbidden'); } }; } uses some() to check if any role matches, then calls next() or sends 403 correctly. function permitRoles(allowedRoles) { return (req, res, next) => { if (allowedRoles.every(role => role !== req.user.role)) { next(); } else { res.status(403).send('Forbidden'); } }; } reverses logic, allowing access if no match, which is wrong.Step 3: Choose best correct code
function permitRoles(allowedRoles) { return (req, res, next) => { if (allowedRoles.some(role => role === req.user.role)) { next(); } else { res.status(403).send('Forbidden'); } }; } correctly implements the logic with proper flow control.Final Answer:
Uses some() to allow access if any role matches, else sends 403 -> Option BQuick Check:
Use some() to check roles and control flow correctly [OK]
- Not returning after sending response
- Using every() incorrectly
- Calling next() even after forbidden response
