Permission middleware helps control who can access certain parts of a web app. It checks if a user has the right permissions before allowing them to continue.
Permission middleware in Express
Start learning this pattern below
Jump into concepts and practice - no test required
or
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Introduction
Syntax
Express
function permissionMiddleware(requiredPermission) {
return function (req, res, next) {
const userPermissions = req.user?.permissions || [];
if (userPermissions.includes(requiredPermission)) {
next();
} else {
res.status(403).send('Access denied');
}
};
}The middleware is a function that returns another function to use in routes.
It checks if the user's permissions include the required one, then calls next() to continue.
Examples
Express
app.get('/admin', permissionMiddleware('admin'), (req, res) => { res.send('Welcome Admin'); });
Express
app.post('/edit', permissionMiddleware('edit'), (req, res) => { res.send('Edit allowed'); });
Sample Program
This example sets up a simple Express server. It adds a mock user with 'read' and 'edit' permissions. The permission middleware checks if the user can access each route. The '/delete' route will deny access because the user lacks 'delete' permission.
Express
import express from 'express'; const app = express(); // Mock user data middleware app.use((req, res, next) => { req.user = { permissions: ['read', 'edit'] }; next(); }); function permissionMiddleware(requiredPermission) { return (req, res, next) => { const userPermissions = req.user?.permissions || []; if (userPermissions.includes(requiredPermission)) { next(); } else { res.status(403).send('Access denied'); } }; } app.get('/read', permissionMiddleware('read'), (req, res) => { res.send('Reading content'); }); app.post('/edit', permissionMiddleware('edit'), (req, res) => { res.send('Editing content'); }); app.delete('/delete', permissionMiddleware('delete'), (req, res) => { res.status(403).send('Access denied'); }); // Start server app.listen(3000, () => { console.log('Server running on http://localhost:3000'); });
Important Notes
Always attach user info to req.user before using permission middleware.
Return a 403 status code for forbidden access to follow web standards.
Middleware can be reused for different permissions by passing different strings.
Summary
Permission middleware controls access based on user rights.
It checks user permissions before allowing route handlers to run.
Use it to protect sensitive or restricted parts of your app.
Practice
1. What is the main purpose of permission middleware in an Express app?
easy
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]
Hint: Permission middleware controls access before route runs [OK]
Common Mistakes:
- Confusing permission middleware with logging middleware
- Thinking it formats response data
- Assuming it handles errors
2. Which of the following is the correct way to define a permission middleware function in Express?
easy
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]
Hint: Middleware needs three params: req, res, next [OK]
Common Mistakes:
- Missing next parameter
- Calling next() without parentheses
- Not sending response or calling next() properly
3. Given this middleware and route, what will be the response if req.user.role is 'guest'?
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');
});medium
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]
Hint: If role not admin, middleware sends 403 and stops [OK]
Common Mistakes:
- Assuming route handler runs anyway
- Confusing status codes
- Missing optional chaining on req.user
4. Identify the error in this permission middleware code:
function checkPermission(req, res, next) {
if (!req.user.permissions.includes('edit')) {
res.status(401).send('Unauthorized');
}
next();
}medium
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]
Hint: Return after res.send() to prevent next() running [OK]
Common Mistakes:
- Not returning after sending response
- Using wrong HTTP status code
- Assuming next() should never be called
5. You want to create a permission middleware that allows access only if the user has at least one role from an array of allowed roles. Which code correctly implements this?
hard
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]
Hint: Use some() to check if user role is in allowed roles [OK]
Common Mistakes:
- Not returning after sending response
- Using every() incorrectly
- Calling next() even after forbidden response
