AutoPart Pro uses a stateless authentication model: the server never stores session data. Instead, every user receives a signed JSON Web Token (JWT) upon login or registration. The client stores that token inDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/JFKoryy/autopart-pro/llms.txt
Use this file to discover all available pages before exploring further.
localStorage and attaches it to every subsequent request via an Authorization: Bearer header. The backend verifies the token’s signature and expiry on each request using the protect middleware, and then the authorize middleware checks whether the user’s role permits the requested action.
Registration Flow
New accounts are created by posting credentials to the publicPOST /api/auth/register endpoint. All newly registered users receive the client role.
Validate required fields
The controller checks that
name, email, and password are all present in req.body. A missing field returns 400 Bad Request.Check email uniqueness
UserModel.findByEmail(email) queries the database. If a matching record is found the request is rejected with 400 and the message "El correo electrónico ya está registrado.".Hash the password
bcrypt.genSalt(10) generates a salt and bcrypt.hash(password, salt) produces the hash that is stored in the users.password column. The plain-text password is never persisted.Insert the user record
UserModel.create(name, email, hashedPassword) executes the INSERT. The returned insertId becomes the new user’s id.Sign the JWT
A token is signed with the payload
{ id: userId, role: 'client' }, the JWT_SECRET environment variable, and expiresIn: '1h'.Return token and user
The endpoint responds with Note: the
201 Created and the body shown below. The client stores token in localStorage and keeps user in AuthContext state.user.role field in the registration response body is "user" (a hardcoded string in authController.js), while the JWT payload itself encodes role: 'client'. The frontend’s AuthContext decodes the JWT to determine the actual role — "client" — rather than reading user.role from the registration response directly.Login Flow
Existing users authenticate viaPOST /api/auth/login.
Look up the user by email
UserModel.findByEmail(email) queries the database. A non-existent email returns 400 with the generic message "Credenciales inválidas." — the same message used for a wrong password, to avoid user enumeration.Compare the password
bcrypt.compare(password, user.password) validates the plain-text input against the stored hash. A mismatch returns 400 "Credenciales inválidas.".Sign the JWT
On success a token is signed with
{ id: user.id, role: user.role } and expiresIn: '1h'. Unlike registration, the role in the payload reflects the user’s actual stored role, which may be admin, employee, or client.Token Structure
Every JWT issued by AutoPart Pro carries the same two claims in its payload:| Claim | Value | Description |
|---|---|---|
id | Integer | The user’s primary key in the users table |
role | "admin" | "employee" | "client" | Determines which endpoints and UI features are accessible |
iat | Unix timestamp | Issued-at — added automatically by jsonwebtoken |
exp | Unix timestamp | Expiry — 1 hour after iat |
AuthContext initialises the user state by base64-decoding the JWT payload from localStorage on first load — this avoids an extra network round-trip before the token re-validation request completes:
protect Middleware
The protect middleware in backend/src/middleware/authMiddleware.js gates every route that requires authentication. It is applied before any controller that should not be publicly accessible.
- Extracts the token from the
Authorization: Bearer <token>header. A missing or malformed header yields401. - Verifies the signature and expiry using
jwt.verify()withprocess.env.JWT_SECRET. An invalid or expired token yields401. - Injects
req.userwith the decoded payload{ id, role, iat, exp }so all downstream middleware and controllers know who is making the request.
authorize Middleware
The authorize middleware in backend/src/middleware/roleMiddleware.js is used after protect to restrict endpoints to specific roles. It is a higher-order function that accepts one or more allowed role strings:
Frontend Token Storage
The API service layer (frontend/src/services/api.js) reads the token from localStorage and attaches it to every authenticated request using a getAuthHeader() helper:
fetch calls pass this object as headers. The login and register endpoints are public and only send Content-Type: application/json.
Token Validation on Page Load
When the application mounts,AuthContext calls api.validateToken() to confirm the stored token is still valid with the backend. This catches tokens that have been invalidated server-side or have simply expired:
validateToken() calls GET /api/auth/me, which is protected by the protect middleware. If the token is valid the endpoint returns the full user object from the database; if not, the token is removed from localStorage and the user is treated as unauthenticated.
Example: Login with curl
200 OK):
400 Bad Request):
Endpoint Authorization Reference
The table below maps every API endpoint to its authentication and role requirements.| Method | Path | Auth required | Allowed roles |
|---|---|---|---|
POST | /api/auth/register | No | — |
POST | /api/auth/login | No | — |
GET | /api/auth/me | Yes (protect) | Any authenticated |
GET | /api/auth/profile | Yes (protect) | Any authenticated |
GET | /api/products | No | — |
GET | /api/products/low-stock | Yes (protect) | Any authenticated |
GET | /api/products/:id | Yes (protect) | Any authenticated |
POST | /api/products | Yes (protect) | admin |
PUT | /api/products/:id | Yes (protect) | admin |
DELETE | /api/products/:id | Yes (protect) | admin |
GET | /api/sales | Yes (protect) | Any authenticated |
POST | /api/sales | Yes (protect) | Any authenticated |
GET | /api/users | Yes (protect) | admin |
PUT | /api/users/:id/role | Yes (protect) | admin |
DELETE | /api/users/:id | Yes (protect) | admin |
GET | /api/health | No | — |
GET /api/sales returns all sales to admin users and only the requesting user’s own sales to client users. The role filtering is handled inside saleController.js, not at the middleware layer.