Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/vanegasjoseignacio2-cyber/Eco-It/llms.txt

Use this file to discover all available pages before exploring further.

Eco-It’s local authentication flow keeps account creation safe by requiring every new user to verify their email address before their account is created in the database. A temporary PendingRegistration document holds the user’s details and a hashed 6-digit code for up to 15 minutes. Only after a successful code verification is the permanent User document written to MongoDB and a JWT issued. This page documents every endpoint, field requirement, and error case in the local auth flow.

Registration flow

Registration is a two-request handshake. The first request sends a verification code to the user’s email; the second verifies that code and creates the account. A separate resend endpoint lets users request a fresh code if theirs expires or gets lost.
1

Send the verification code

Submit the user’s full registration details to request a 6-digit code. The backend validates all fields, checks that the email is not already registered, hashes the password, and emails the code before writing anything to the database — if the email delivery fails, no record is created.Endpoint: POST /api/auth/enviar-codigo-registroRequest body:
nombre
string
required
First name. 2–50 characters.
apellido
string
required
Last name.
email
string
required
Valid email address. Must not already have an active account.
password
string
required
Plain-text password. Minimum 8 characters (enforced by the User model schema). The backend hashes it with bcrypt (salt rounds: 12) before storing in PendingRegistration.
telefono
string
required
Mobile phone number. Validated with isMobilePhone().
edad
number
required
User’s age. Stored as an integer.
curl -X POST https://api.eco-it.co/api/auth/enviar-codigo-registro \
  -H "Content-Type: application/json" \
  -d '{
    "nombre": "Laura",
    "apellido": "Ramírez",
    "email": "laura@example.com",
    "password": "MiClave2024!",
    "telefono": "+573001234567",
    "edad": 28
  }'
Success response 200:
{
  "success": true,
  "mensaje": "Código enviado a tu correo electrónico."
}
A 3-minute cooldown applies between code requests for the same email. If a pending registration already exists with more than 12 minutes remaining on its 15-minute timer (i.e., fewer than 3 minutes have passed since the last request), the server returns 429 with the number of minutes to wait.
2

Verify the code and create the account

Submit the email and the 6-digit code from the email. The backend hashes the submitted code with SHA-256 and compares it against the stored hash. On success, it creates the User document, deletes the PendingRegistration record, sends a welcome email, and returns a JWT.Endpoint: POST /api/auth/verificar-registro
email
string
required
The same email used in step 1.
codigo
string
required
The 6-digit verification code received by email.
curl -X POST https://api.eco-it.co/api/auth/verificar-registro \
  -H "Content-Type: application/json" \
  -d '{
    "email": "laura@example.com",
    "codigo": "382910"
  }'
Success response 201:
{
  "success": true,
  "mensaje": "¡Cuenta verificada y creada exitosamente!",
  "data": {
    "token": "<jwt>",
    "usuario": {
      "id": "664f1a2b3c4d5e6f7a8b9c0d",
      "nombre": "Laura",
      "apellido": "Ramírez",
      "email": "laura@example.com",
      "telefono": "+573001234567",
      "edad": 28,
      "rol": "user",
      "perfilCompleto": true
    }
  }
}
The code expires after 15 minutes. After 5 consecutive incorrect attempts the pending registration is deleted and the user must start over from step 1. Each incorrect attempt returns the number of remaining tries in the mensaje field.
3

Resend the verification code

If the code was not received or has expired, users can request a new one without resubmitting their full details.Endpoint: POST /api/auth/reenviar-codigo-registro
email
string
required
Email address of the pending registration.
curl -X POST https://api.eco-it.co/api/auth/reenviar-codigo-registro \
  -H "Content-Type: application/json" \
  -d '{ "email": "laura@example.com" }'
Success response 200:
{
  "success": true,
  "mensaje": "Nuevo código enviado a tu correo."
}

Login

After an account is created (or on subsequent visits), users authenticate by submitting their email and password. The backend uses bcrypt’s compare to validate the password against the hashed value stored in MongoDB (the password field is excluded from queries by default via select: false in the schema — the login controller explicitly re-includes it with .select('+password')). Endpoint: POST /api/auth/login
email
string
required
Registered email address.
password
string
required
Plain-text password.
curl -X POST https://api.eco-it.co/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "laura@example.com",
    "password": "MiClave2024!"
  }'
Success response 200:
{
  "message": "Inicio de sesión correcto",
  "data": {
    "token": "<jwt>",
    "usuario": {
      "id": "664f1a2b3c4d5e6f7a8b9c0d",
      "nombre": "Laura",
      "apellido": "Ramírez",
      "edad": 28,
      "email": "laura@example.com",
      "telefono": "+573001234567",
      "rol": "user",
      "perfilCompleto": true
    }
  }
}
token
string
A signed JWT valid for 12 hours. Store this in localStorage under the key token and include it in subsequent requests as Authorization: Bearer <token>.
usuario
object
The authenticated user’s profile data, excluding the password hash.
If the account was created with Google OAuth and has no local password set, the login endpoint returns 401 with the message: “Este usuario se registró con Google. Por favor, inicia sesión con Google.” Direct users to the Google OAuth flow in this case.

Logout

Logout is handled client-side by removing the token from localStorage. The server endpoint exists for audit-log purposes and to invalidate any future server-side session state. Endpoint: POST /api/auth/logout
curl -X POST https://api.eco-it.co/api/auth/logout
Response 200:
{
  "success": true,
  "message": "Sesión cerrada correctamente"
}

Validation rules

The validarRegistro and validarLogin middlewares from validation.js run before the controllers and return a 400 response with a structured errores array if any field is invalid.

Registration (validarRegistro)

FieldRule
nombreRequired · 2–50 characters (trimmed)
emailRequired · valid email format · normalized to lowercase
passwordRequired · minimum 6 characters (middleware) — the User schema itself enforces 8 characters as a floor
The validarRegistro middleware is attached to the legacy POST /api/auth/registro route, which now returns 400 directing clients to use the two-step email verification flow instead. The enviarCodigoRegistro controller performs its own inline field checks for the full set of registration fields (nombre, apellido, edad, email, telefono, password).

Login (validarLogin)

FieldRule
emailRequired · valid email format (trimmed)
passwordRequired (non-empty)

Profile completion (validarPerfilCompleto)

FieldRule
apellidoRequired (trimmed, non-empty)
edadInteger between 1 and 120
telefonoRequired · valid mobile phone format

Password hashing

Eco-It uses bcrypt with a salt factor of 10 for all local passwords. Hashing is performed in a Mongoose pre('save') hook on the User model. The hook is skipped when this.$skipPasswordHash is set to true (used during email-verification registration, where the password is already hashed in PendingRegistration) or when the password field has not been modified.
// From backend/models/user.js
userSchema.pre('save', async function () {
  if (this.$skipPasswordHash || !this.isModified('password') || !this.password) {
    return;
  }
  const salt = await bcrypt.genSalt(10);
  this.password = await bcrypt.hash(this.password, salt);
});

Profile completion (for Google OAuth users)

Google OAuth users are created without edad or telefono, and apellido is only set when Google returns a family name. Their perfilCompleto flag is always set to false at creation. After their first login they must complete their profile before accessing the full platform. This endpoint is also available to any authenticated user who needs to update these fields. Endpoint: PUT /api/auth/completar-perfil Requires: Authorization: Bearer <token>
apellido
string
required
Last name (trimmed, non-empty).
edad
number
required
Integer between 1 and 120.
telefono
string
required
Valid mobile phone number.
curl -X PUT https://api.eco-it.co/api/auth/completar-perfil \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <token>" \
  -d '{
    "apellido": "González",
    "edad": 31,
    "telefono": "+573109876543"
  }'
Success response 200:
{
  "success": true,
  "usuario": {
    "_id": "664f1a2b3c4d5e6f7a8b9c0d",
    "nombre": "Carlos",
    "apellido": "González",
    "email": "carlos@gmail.com",
    "telefono": "+573109876543",
    "edad": 31,
    "perfilCompleto": true
  }
}
After calling this endpoint, the frontend should request a fresh JWT (via login or a token-refresh mechanism) so that the new perfilCompleto: true claim is reflected in the token payload and PrivateRoute guards work correctly.

Build docs developers (and LLMs) love