Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Medinaallan/ContabilidadISV/llms.txt

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

ContabilidadISV’s authentication system is built on JSON Web Tokens (JWT). The flow is straightforward: the client POSTs credentials to POST /api/auth/login, receives a signed JWT in the response, and stores it in localStorage (frontend) or in your HTTP client’s state. Every subsequent request to a protected endpoint must include the token in the Authorization header in the form Authorization: Bearer <token>. On the server side, the authenticateToken middleware verifies the token signature and confirms that the corresponding user still exists in the database before allowing the request to proceed.
All endpoints except POST /api/auth/login and POST /api/auth/register require a valid JWT token passed in the Authorization: Bearer <token> header.

Obtaining a Token

POST /api/auth/login

Validates the supplied credentials and returns a signed JWT along with the authenticated user’s profile. Failed attempts are recorded in the database and contribute to rate-limiting counters.

Request Body

username
string
required
The account username. Must be at least 3 characters long.
password
string
required
The account password. Cannot be empty.

Response

message
string
Human-readable confirmation, e.g. "Login exitoso".
token
string
Signed JWT bearer token. Include this value in the Authorization: Bearer <token> header on all authenticated requests. Expires according to the JWT_EXPIRES_IN environment variable (defaults to 24h).
user
object
The authenticated user’s profile.

Error Responses

StatusMeaning
400Validation error — username or password did not pass input validation. The response body contains a details array with field-level messages.
401Invalid credentials — username not found or password mismatch. The response body is { "error": "Credenciales inválidas" }.
500Internal server error.

Example

curl -s -X POST https://your-api.example.com/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "username": "jsmith",
    "password": "s3cur3P@ss"
  }'

Registering a User

POST /api/auth/register

Creates a new user account and immediately returns a JWT so the client can proceed without a separate login step. In most deployments this endpoint is used for initial setup or by administrators to onboard new users.

Request Body

username
string
required
Desired username. Must be between 3 and 30 characters after trimming whitespace.
email
string
required
Valid email address. The value is normalized (lowercased, extraneous dots removed) before storage.
password
string
required
Account password. Minimum 6 characters. Stored as a bcrypt hash (12 salt rounds).
role
'user' | 'admin'
default:"user"
Role to assign. Optional. Must be exactly "user" or "admin" if provided; defaults to "user".

Validation Rules (enforced by express-validator)

FieldRule
usernameTrimmed; length 3–30 characters
emailMust pass isEmail() check; normalized before storage
passwordMinimum 6 characters
roleOptional; must be "user" or "admin" if present

Response

Same shape as the login response:
message
string
"Usuario registrado exitosamente"
token
string
Signed JWT bearer token for the newly created account.
user
object

Error Responses

StatusMeaning
400Validation error or email already registered.
500Internal server error.

Example

curl -s -X POST https://your-api.example.com/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "username": "nuevo_contador",
    "email": "contador@empresa.hn",
    "password": "M1Cl4ve!",
    "role": "user"
  }'

Token Validation

GET /api/auth/validate

Verifies that the bearer token in the request header is still valid and that the associated user exists in the database. Use this endpoint in client-side route guards or app initialization to quickly check session state. Requires: Authorization: Bearer <token>

Response

valid
boolean
Always true when the request succeeds (a failed token produces a 401/403 error, not false).
user
object

Error Responses

StatusMeaning
401No token provided, or the token’s user no longer exists in the database.
403Token present but signature verification failed (expired or tampered).

Example

curl -s https://your-api.example.com/api/auth/validate \
  -H "Authorization: Bearer $TOKEN"

Get Profile

GET /api/auth/profile

Returns the full profile record for the currently authenticated user as stored in the database. Unlike the token payload — which is static for the token’s lifetime — this endpoint reflects any updates made to the user record after the token was issued. Requires: Authorization: Bearer <token>

Response

user
object

Error Responses

StatusMeaning
401Missing or invalid token.
404User referenced by the token no longer exists.
500Internal server error.

Example

curl -s https://your-api.example.com/api/auth/profile \
  -H "Authorization: Bearer $TOKEN"

Logout

POST /api/auth/logout

Records a USER_LOGOUT event in the system log (capturing IP address and User-Agent) and confirms the session has been closed. Because ContabilidadISV uses stateless JWTs, the token is not blocklisted server-side — the client is responsible for deleting it from localStorage. Requires: Authorization: Bearer <token>

Response

message
string
"Logout exitoso"

Error Responses

StatusMeaning
401Missing or invalid token.
500Internal server error (log creation failed).

Example

curl -s -X POST https://your-api.example.com/api/auth/logout \
  -H "Authorization: Bearer $TOKEN"

Admin Endpoints

The following endpoints require both a valid token and the admin role. Requests from user-role accounts receive a 403 Forbidden response.

GET /api/auth/login-history

Returns a paginated list of login attempts recorded in the database (both successful and failed). Requires: Authorization: Bearer <token> · role: admin

Query Parameters

username
string
Filter attempts by username (partial or exact, depending on DB implementation).
ipAddress
string
Filter attempts originating from a specific IP address.
hoursBack
number
default:"24"
How many hours into the past to look. Defaults to 24.
failedOnly
boolean
default:"false"
When "true", return only failed attempts.

Response

success
boolean
true on success.
count
number
Total number of records returned.
attempts
array
Array of login-attempt objects.

Example

curl -s "https://your-api.example.com/api/auth/login-history?hoursBack=48&failedOnly=true" \
  -H "Authorization: Bearer $TOKEN"

GET /api/auth/failed-login-stats

Aggregates failed login attempts by IP address over a configurable time window. Use this to identify brute-force patterns. Requires: Authorization: Bearer <token> · role: admin

Query Parameters

ipAddress
string
Narrow results to a specific IP address.
minutesBack
number
default:"30"
Time window in minutes. Defaults to 30.

Response

success
boolean
true on success.
count
number
Number of distinct IP entries returned.
stats
array

Example

curl -s "https://your-api.example.com/api/auth/failed-login-stats?minutesBack=60" \
  -H "Authorization: Bearer $TOKEN"

POST /api/auth/clean-login-attempts

Purges login attempt records older than the specified number of days. Run periodically to keep the login_attempts table lean. Requires: Authorization: Bearer <token> · role: admin

Request Body

daysToKeep
number
default:"30"
Records older than this many days will be deleted. Defaults to 30.

Example

curl -s -X POST https://your-api.example.com/api/auth/clean-login-attempts \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "daysToKeep": 14 }'

Using the Token

Frontend — Axios interceptor (from api.ts)

The React frontend configures an Axios instance that automatically attaches the stored token to every outgoing request and handles 401 responses by clearing state and redirecting to the login page:
axios-interceptor.ts
import axios from 'axios';

const api = axios.create({
  baseURL: '/api',
  timeout: 30000,
});

// Attach token from localStorage to every request
api.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

// On 401, clear auth state and redirect to login
api.interceptors.response.use(
  (response) => response,
  (error) => {
    if (error.response?.status === 401) {
      localStorage.removeItem('token');
      localStorage.removeItem('user');
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);
After a successful login the token and user data are persisted to localStorage:
store-token.ts
// After POST /api/auth/login
const { token, user } = response.data;
localStorage.setItem('token', token);
localStorage.setItem('user', JSON.stringify(user));

Any HTTP client

You can replicate the same pattern in any language or tool — the only requirement is the Authorization header:
# 1. Login and extract token
TOKEN=$(curl -s -X POST https://your-api.example.com/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"jsmith","password":"s3cur3P@ss"}' \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['token'])")

# 2. Use the token on a protected endpoint
curl -s https://your-api.example.com/api/auth/profile \
  -H "Authorization: Bearer $TOKEN"

localStorage and XSS risk. The ContabilidadISV frontend stores the JWT in localStorage, which is accessible to any JavaScript running on the page. In production environments with strict security requirements — especially where XSS is a concern — consider migrating token storage to HttpOnly cookies managed by the server. HttpOnly cookies are invisible to JavaScript and provide a stronger security boundary. See Security Configuration for related hardening options.

Build docs developers (and LLMs) love