User Authentication
Relevant source files
The following files were used as context for generating this wiki page:
The User Authentication system provides core functionality for user registration, login, and session management. It is built on a standard email/password authentication pattern, using JSON Web Tokens (JWT) to secure API endpoints. The backend is handled by an Express.js server, while the frontend is a React application.
The system is designed to differentiate between user roles, such as User and Admin, enabling role-based access control for different parts of the application. Secure practices like password hashing are implemented on the backend to protect user credentials.
System Architecture
The authentication system follows a client-server model. The React frontend communicates with the Express.js backend via a RESTful API. The backend processes authentication requests, interacts with a MongoDB database for user data persistence, and issues JWTs for session management.
This diagram illustrates the high-level interaction between the components.
Backend Implementation
The backend is responsible for handling all authentication logic, including user validation, password management, and token generation.
Sources: backend/src/routes/auth.js, backend/src/models/TaiKhoan.js, backend/src/middleware/auth.js
API Endpoints
The authentication API is exposed under the /api/auth base path.
| Method | Endpoint | Description |
|---|---|---|
POST | /api/auth/register | Creates a new user account. Requires name, email, and password. |
POST | /api/auth/login | Authenticates a user with email and password, and returns a JWT. |
POST | /api/auth/logout | A stateless endpoint that allows the client to perform logout operations. |
Sources: backend/src/routes/auth.js:15-151
Data Model (TaiKhoan)
User account information is stored in the TaiKhoan collection in MongoDB. The Mongoose schema defines the structure and validation rules for user data.
This diagram shows the entity relationship for the TaiKhoan model.
Sources: backend/src/models/TaiKhoan.js:10-44
Key fields and their properties are detailed below:
| Field | Type | Constraints | Description |
|---|---|---|---|
_id | String | Required, Custom format (TKxx) | The primary key, generated manually. |
TenDangNhap | String | Required, Unique | The user's login name. |
HoTen | String | - | The user's full name. |
Email | String | Required, Unique, Valid email format | The user's email address, used for login. |
MatKhau | String | Required, Min length 6, select: false | The user's hashed password. Not returned in queries by default. |
VaiTro | Array | Enum: User, Admin, Technician | An array of roles assigned to the user. |
TrangThai | String | Enum: active, locked, etc. Default: active | The current status of the user account. |
Sources: backend/src/models/TaiKhoan.js:10-44, backend/src/routes/taiKhoan.js:150
Password Hashing
To securely store user passwords, the system uses bcryptjs. A pre-save middleware hook in the TaiKhoan Mongoose schema automatically hashes the password before it is saved to the database.
// backend/src/models/TaiKhoan.js:77-89
taiKhoanSchema.pre("save", async function (next) {
if (!this.isModified("MatKhau")) {
return next();
}
try {
const salt = await bcrypt.genSalt(12);
this.MatKhau = await bcrypt.hash(this.MatKhau, salt);
next();
} catch (error) {
next(error);
}
});
During login, the comparePassword instance method is used to compare the provided password with the stored hash.
Sources: backend/src/models/TaiKhoan.js:77-94, backend/src/routes/auth.js:115-116
JWT Session Management
Upon successful login, the server generates a JWT using the jsonwebtoken library. The token payload contains the user's ID, which is used to identify the user in subsequent requests.
The signToken function creates a token that expires in 7 days by default.
// backend/src/routes/auth.js:10-14
const signToken = (id) => {
return jwt.sign({ id }, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRES_IN || "7d",
});
};
The generated token is sent back to the client in the JSON response body. An alternative implementation in authController.js demonstrates sending the token in a secure, httpOnly cookie, which is a more secure approach against XSS attacks.
Sources: backend/src/routes/auth.js:10-14, 121-122, backend/src/controllers/authController.js:13-22
Authorization Middleware
Protected routes are secured using custom middleware.
protect: This middleware verifies the JWT. It first attempts to read the token from an HTTP-only cookie and falls back to checking theAuthorization: Bearer <token>header. If the token is valid, it decodes the payload and attaches the user's information (id,role) to thereqobject.authorize(...roles): This is a higher-order function that checks if the authenticated user's role (fromreq.user.role) is included in the list of allowed roles.
Sources: backend/src/middleware/auth.js:7-39
Frontend Implementation
The frontend React application provides the user interface for authentication and manages the user's session state.
Sources: frontend/src/pages/Sign_in.js, frontend/src/pages/Register.js, frontend/src/services/authAPI.js
UI Components
Register.js: A page component with a form for new users to sign up. It collects a name, email, and password, performs basic validation (e.g., password confirmation), and calls the registration service.Sign_in.js: A page component with a form for existing users to log in. It collects an email and password and calls the login service. Upon successful login, it redirects the user to the appropriate dashboard based on their role (/admin/overviewfor Admins,/dashboardfor Users).
Sources: frontend/src/pages/Register.js, frontend/src/pages/Sign_in.js
API Service (authAPI.js)
All HTTP requests related to authentication are centralized in frontend/src/services/authAPI.js. This file uses axios to create a pre-configured API client.
Key configurations:
baseURL: Set from an environment variableREACT_APP_API_BASEor defaults tohttp://localhost:5001/api.withCredentials: true: This is important for allowing the browser to send cookies with cross-origin requests, which is necessary for cookie-based authentication.
The service exports functions like register(userData) and login(credentials) that map directly to the backend API endpoints.
Sources: frontend/src/services/authAPI.js:5-20, 31-32
State Management (AuthContext)
Although the AuthContext.js file is not fully provided, its usage is evident in the Sign_in.js and Register.js pages via the useAuth() hook. This context is responsible for:
- Providing
loginandregisterfunctions to components. - Managing the global authentication state (e.g., current user, token, loading status).
- Handling and displaying authentication-related errors.
- Persisting the user's session across the application.
Sources: frontend/src/pages/Sign_in.js:16, frontend/src/pages/Register.js:8
Authentication Flows
Registration Flow
The following sequence diagram shows the process of a new user registering for an account.
Login Flow
This diagram illustrates the steps involved when a user logs in.