PortalHub uses PHP server-side sessions for all authentication, meaning no JWT tokens or external auth services are required. Every request that reaches a protected endpoint passes through a sharedDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/Nieto2020/portalhub/llms.txt
Use this file to discover all available pages before exploring further.
checkAuth() middleware function that validates session state, enforces inactivity timeouts, and handles forced password-change workflows before any business logic runs.
Login Flow
The login endpoint (modules/auth/login.php) accepts a JSON POST body and follows a strict sequence to prevent enumeration, session fixation, and brute-force attacks.
Validate Required Fields
The request body must contain
correo and password. Missing fields return 400.Look Up User and Verify Password
A prepared PDO statement fetches
id_usuario, id_rol, password_hash, estado, and require_password_change by email. The stored hash is verified with PHP’s password_verify(). On failure, a sleep(1) delay is applied before returning 401 to slow brute-force attempts.Check Account Status
If
estado !== 'activo' the login is rejected with 403. Inactive accounts cannot authenticate regardless of credential correctness.Regenerate Session ID
session_regenerate_id(true) is called before writing any session data, eliminating session-fixation vulnerabilities.Write Session Variables
Four keys are stored in
$_SESSION:id_usuario— numeric user primary keyid_rol— role constant (ROL_ADMIN = 1,ROL_ASESOR = 2,ROL_CLIENTE = 3)require_password_change—0or1ultima_actividad—time()timestamp used for inactivity tracking
- Request
- Success Response (200)
- Inactive User (403)
Session Inactivity Timeout
config.php defines a global constant used by every middleware call:
checkAuth() computes how long ago the session was last active and destroys it if the threshold is exceeded:
check_session.php calls checkAuth(false) — it verifies the session is alive without refreshing ultima_actividad, making it safe for polling from the frontend without extending an otherwise-idle session.Forced Password Change
Whenrequire_password_change = 1 is set on a user account (for example, on first login or after an admin reset), every endpoint except the three below is blocked with 403:
update_password.phplogout.phpcheck_session.php
update_password.php requires the CSRF token and validates that both new_password and confirm_password match and are at least 8 characters long. The password is hashed with PASSWORD_BCRYPT. After a successful update, require_password_change is set to 0 in both the database and the live session, and a fresh CSRF token is issued.
CSRF Protection
CSRF tokens are 32 random bytes encoded as a 64-character hexadecimal string:GET modules/auth/csrf_token.php. All mutating endpoints that handle sensitive data (such as update_password.php) validate the token using a constant-time comparison:
Role-Based Access Control
checkRole() extends checkAuth() with an array of allowed role IDs. Any request from a user whose id_rol is not in that array receives 403:
config.php:
| Constant | Value | Description |
|---|---|---|
ROL_ADMIN | 1 | Full administrative access |
ROL_ASESOR | 2 | Accounting advisor |
ROL_CLIENTE | 3 | End-client portal user |
Logout
logout.php performs a clean session teardown and explicitly expires the session cookie to prevent replay:
Cookie Security Settings
config.php configures PHP’s session cookie with security-first defaults before any session_start() call:
| Setting | Value | Purpose |
|---|---|---|
session.cookie_httponly | 1 | Prevents JavaScript access to the session cookie |
session.cookie_secure | Auto-detected | Cookie sent over HTTPS only when HTTPS is active |
session.use_only_cookies | 1 | Disables session ID in URL query strings |
session.cookie_samesite | Lax | Mitigates cross-site request forgery via cookies |