Authentication & Authorization Middleware
Relevant source files
The following files were used as context for generating this wiki page:
The authentication and authorization system is a critical security component of the backend, responsible for protecting API endpoints. It ensures that only authenticated users with the correct permissions can access specific resources. The system is built as a series of Express.js middleware functions that leverage JSON Web Tokens (JWT) stored in HTTP-only cookies.
This system differentiates between three main roles: standard users (user), shop owners (Seller), and Admin. Each role has a distinct authentication flow and level of access, which is enforced by a combination of middleware functions applied at the application and route levels.
Sources: backend/middleware/auth.js, README.md
Core Middleware Components
The security layer is composed of three primary middleware functions defined in backend/middleware/auth.js. These functions are used to guard routes and verify user identity and roles.
Sources: backend/middleware/auth.js
| Function | Cookie Name | Description |
|---|---|---|
isAuthenticated | token | Verifies the JWT for a standard user. If valid, it fetches the user's data from the User model and attaches it to req.user. |
isSeller | seller_token | Verifies the JWT for a seller. If valid, it fetches the shop's data from the Shop model and attaches it to req.seller. |
isAdmin | token | A higher-order function that checks if the req.user.role (populated by isAuthenticated) matches one of the specified roles (e.g., "Admin"). |
Sources: backend/middleware/auth.js:7-36
isAuthenticated
This middleware is the foundation for user authentication. It extracts the JWT from a cookie named token. If the token is missing, it returns a 401 Unauthorized error. If present, it verifies the token using the JWT_SECRET. On successful verification, it uses the decoded user ID to retrieve the full user object from the database and attaches it to the req.user object for use in subsequent middleware or route handlers.
// backend/middleware/auth.js:7-16
exports.isAuthenticated = catchAsyncErrors(async(req,res,next) => {
const {token} = req.cookies;
if(!token){
return next(new ErrorHandler("Vui lòng đăng nhập để tiếp tục", 401));
}
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = await User.findByPk(decoded.id);
next();
});
Sources: backend/middleware/auth.js:7-16
The following diagram illustrates the process flow of the isAuthenticated middleware.
Sources: backend/middleware/auth.js:7-16
isSeller
This middleware functions identically to isAuthenticated but is specific to sellers. It looks for a seller_token cookie, verifies it, and attaches the seller's shop data to req.seller. This allows the application to maintain separate login sessions for users and sellers.
// backend/middleware/auth.js:19-28
exports.isSeller = catchAsyncErrors(async(req,res,next) => {
const {seller_token} = req.cookies;
if(!seller_token){
return next(new ErrorHandler("Vui lòng đăng nhập để tiếp tục", 401));
}
const decoded = jwt.verify(seller_token, process.env.JWT_SECRET);
req.seller = await Shop.findByPk(decoded.id);
next();
});
Sources: backend/middleware/auth.js:19-28
isAdmin
This is a higher-order function that provides role-based access control (RBAC). It takes a list of roles as arguments and returns a middleware function. This returned middleware checks if the role property of the req.user object (which must be populated by isAuthenticated first) is included in the list of allowed roles. If the user's role is not permitted, it returns an error.
// backend/middleware/auth.js:31-37
exports.isAdmin = (...roles) => {
return (req,res,next) => {
if(!roles.includes(req.user.role)){
return next(new ErrorHandler(`${req.user.role} không thể truy cập tài nguyên này!`))
};
next();
}
}
Sources: backend/middleware/auth.js:31-37
Authentication and Authorization Flows
User Login and Token Generation
The authentication process begins when a user submits their credentials to the /api/v2/user/login-user endpoint. The server validates the email and password. If they are correct, the sendToken utility is called, which generates a JWT and sends it back to the client as an HTTP-only cookie named token. This cookie is then automatically included in subsequent requests to the server.
The diagram below shows the sequence of events during user login.
Sources: backend/controller/user.js:132-152
Protected Route Access
Once authenticated, any request to a protected endpoint triggers the associated middleware. For example, a request to /api/v2/user/getuser is first intercepted by isAuthenticated.
This middleware chaining is fundamental to the application's security. An endpoint can be protected by one or more middleware functions, creating a pipeline of checks that a request must pass through.
The following example from app.js shows how multiple middleware functions are chained to protect an admin-only route. The request must first pass isAuthenticated to verify the user's identity, and then isAdmin('Admin') to verify their role.
// backend/app.js:95-98
app.put(
"/api/v2/user/update-role/:id",
require("./middleware/auth").isAuthenticated,
require("./middleware/auth").isAdmin("Admin"),
// ... route handler
);
Sources: backend/app.js:95-98
Middleware Integration Examples
The authentication and authorization middleware are applied across various controllers to protect different resources based on user roles.
| Protected Route | HTTP Method | Middleware Used | File | Description |
|---|---|---|---|---|
/getuser | GET | isAuthenticated | backend/controller/user.js | Retrieves the profile of the currently logged-in user. |
/update-user-info | PUT | isAuthenticated | backend/controller/user.js | Allows a logged-in user to update their own profile information. |
/delete-shop-product/:id | DELETE | isSeller | backend/controller/product.js | Allows a logged-in seller to delete one of their products. |
/create-new-review | PUT | isAuthenticated | backend/controller/product.js | Allows a logged-in user to post a review for a product. |
/get-all-withdraw-request | GET | isAuthenticated, isAdmin('Admin') | backend/controller/withdraw.js | Allows an admin to view all withdrawal requests from sellers. |
/admin-all-users | GET | isAuthenticated, isAdmin('Admin') | backend/controller/user.js | Allows an admin to retrieve a list of all users. |
Sources: backend/controller/user.js:155-156, 202-203, 401-403, backend/controller/product.js:122-124, 219-221, backend/controller/withdraw.js:60-62