Blackterz uses JSON Web Tokens (JWT) for stateless authentication and bcrypt (10 salt rounds) for password hashing. Every request to a protected endpoint must include anDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/Blackterz2/Proyecto_5to_Semestre/llms.txt
Use this file to discover all available pages before exploring further.
Authorization: Bearer <token> header. Tokens are issued on registration and login, stored client-side in localStorage, and expire after 7 days.
Registration
New accounts are created withPOST /api/auth/register. The server validates that the email is not already in use, hashes the password with bcrypt, and returns a 201 Created response with the new user object.
Validate input
The controller checks that
nombre, email, and password are present, that the email matches the regex /^[^\s@]+@[^\s@]+\.[^\s@]+$/, and that the password is at least 6 characters long.Check email uniqueness
buscarUsuarioPorEmail(email) queries the database. If a row is found, the server responds 409 Conflict — the email is already registered.Hash the password
bcrypt.hash(password, 10) runs the algorithm 2¹⁰ = 1,024 times, generating a unique salt per hash. The stored value looks like $2b$10$<22-char-salt><31-char-hash>.Persist the user
crearUsuario(nombre, email, passwordHash) inserts the new row and returns { id, nombre, email }.Request body
The user’s display name.
A valid email address. Must be unique across all accounts.
Plain-text password. Minimum 6 characters. Never stored — only the bcrypt hash is persisted.
Response fields
"ok" on success.The auto-incremented primary key of the new user.
The user’s display name.
The user’s email address.
Login
POST /api/auth/login verifies credentials and returns a signed JWT valid for 7 days.
Look up the user by email
buscarUsuarioPorEmail(email) is called. If no row is found, the server responds 401 Unauthorized with "Credenciales inválidas" — the same message used for a wrong password, to prevent email enumeration.Check the soft-delete flag
If
usuario.activo === false, the account has been deactivated and the server responds 403 Forbidden — the user is recognized, but access is denied.Compare the password
bcrypt.compare(password, usuario.password) extracts the salt from the stored hash, re-hashes the submitted password with that salt, and compares. Returns false → 401.Sign a JWT
jwt.sign(payload, JWT_SECRET, { expiresIn: '7d' }) creates the token. The payload contains usuario_id, nombre, and email.JWT payload structure
Thejwt.sign call in authController.js includes three application claims plus the standard iat and exp timestamps added automatically by jsonwebtoken:
The JWT payload is base64-encoded, not encrypted. Anyone can decode it. Never put sensitive data (passwords, payment info) in the payload. Security comes from the HMAC-SHA256 signature, which
jwt.verify() validates on every request.Using the Token
After login the frontend stores the token inlocalStorage and attaches it to every subsequent API request via the Authorization header.
Authenticated request
verificarToken middleware runs before every protected controller. It:
- Reads
req.headers.authorization. - Splits on a space and verifies the
Bearerprefix. - Calls
jwt.verify(token, process.env.JWT_SECRET)— this validates the signature and the expiry in a single call. - Attaches the decoded payload to
req.usuarioso controllers can readreq.usuario.usuario_idsafely.
Password Recovery
The recovery flow uses a time-limited, single-use token stored in thepassword_resets table.
Request a reset link
POST /api/auth/forgot-password with { email }. If the email belongs to an active account, the server generates a 64-character hex token (crypto.randomBytes(32).toString('hex')), saves it with a 1-hour expiry, and emails a reset link to the user.Follow the link
The email contains a link to
/reset-password.html?token=<hex>. The page reads the token from the query string.POST /api/auth/forgot-password always responds 200 OK with the same message regardless of whether the email exists. This prevents attackers from probing which addresses are registered.Token Expiration & Rate Limiting
401 responses
A
401 Unauthorized means the token is missing, malformed, or expired. The client should clear localStorage, remove the token, and redirect the user to the login screen.403 responses
A
403 Forbidden on login means the account exists and the password is correct, but the activo column is FALSE. The account was soft-deleted and cannot authenticate.Soft-Delete Guard
When an account is deactivated viaDELETE /api/usuarios/me, the activo column is set to FALSE. The login controller checks this field after verifying the password:
jwt.verify() until they expire naturally after 7 days — so frontend logout (clearing localStorage) should be enforced immediately on deactivation.
API Reference — Authentication
View full request/response schemas, error codes, and live playground for all
/api/auth endpoints.