PortalHub implements role-based access control (RBAC) with three distinct roles. Every protected API endpoint calls theDocumentation 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() or checkRole() middleware function before executing any business logic — if the session is absent, expired, or under-privileged, the request is rejected immediately with a JSON error response and no further code runs.
Role Definitions
Roles are defined as PHP constants inbackend/config/config.php and stored as integers in the cat_roles table and the usuarios.id_rol column.
| Constant | id_rol | Role Name | Description |
|---|---|---|---|
ROL_ADMIN | 1 | Administrador | Full platform control — user management, assignments, reporting dashboard, announcements |
ROL_ASESOR | 2 | Asesor | Accounting advisor — manages assigned clients, appointments, documents, and reports |
ROL_CLIENTE | 3 | Cliente | End client — views own data, uploads documents, messages their advisor, submits ratings |
Middleware: auth.php
Both guard functions live in backend/middleware/auth.php and are required at the top of every protected PHP script.
checkAuth()
Validates that a valid, non-expired session exists and enforces the force-password-change gate.
checkRole()
Calls checkAuth() first, then verifies the session role is in the caller-supplied allowlist.
Permissions Matrix
The table below summarises which roles can access each feature area. Scoping rules for partial access (🔒) are enforced in SQLWHERE clauses within each module, not in the middleware itself.
| Feature / Module | Admin | Asesor | Cliente |
|---|---|---|---|
| User management (CRUD, status, password reset) | ✅ | ❌ | ❌ |
| Assignments (create / close client–advisor pairs) | ✅ | 🔒 view own | ❌ |
| Appointments (schedule, reschedule, cancel) | ✅ | 🔒 own | 🔒 own |
| Documents (upload, download, delete) | ✅ | 🔒 own clients | 🔒 own |
| Payments (register, approve, invoice status) | ✅ | 🔒 own clients | 🔒 own |
| Messages (chat & tickets) | ✅ | 🔒 own conversations | 🔒 own conversations |
| Notifications (broadcast & per-user) | ✅ broadcast | 🔒 own | 🔒 own |
| Reports (create) | ❌ | ✅ own reports only | ❌ |
| Reports (view / list) | ✅ all | 🔒 own | 🔒 own (read-only) |
| Ratings (submit 1–5 star score) | ❌ | ❌ receive only | ✅ submit |
| Announcements (create / toggle active) | ✅ create | 🔒 read only | 🔒 read only |
| Profile (view / edit own profile) | ✅ | ✅ | ✅ |
| Dashboard / Reports overview | ✅ | ✅ | ✅ |
Session Security
Security settings are applied at the PHP level inconfig.php before any session is started:
Session Timeout
SESSION_TIMEOUT is set to 1800 seconds (30 minutes). On every request, checkAuth() computes the elapsed time since $_SESSION['ultima_actividad']. If the gap exceeds 1800 seconds the session is destroyed and a 401 response is returned. The ultima_actividad timestamp is refreshed on every successful request unless checkAuth(false) is called explicitly (used by check_session.php to probe status without resetting the clock).
Session Fixation Protection
On every successful loginsession_regenerate_id(true) is called immediately before writing session variables. This issues a new session ID and invalidates the previous one, preventing session fixation attacks:
CSRF Token
A 64-character hexadecimal CSRF token is generated withbin2hex(random_bytes(32)) on each login and stored in $_SESSION['csrf_token']. State-changing frontend requests must include this token, which the backend validates before processing.
Force Password Change
New accounts created viaregister.php have require_password_change = 1 in the database. The value is loaded into the session at login:
checkAuth() checks this flag. If it equals 1, the only permitted endpoints are:
update_password.php— allows the user to set a new passwordlogout.php— allows them to exit without completing the changecheck_session.php— passive session-status probe used by the frontend
require_password_change: true flag in the response data and redirects the user to the password-change page automatically.
Admin Password Reset Audit
When an administrator resets a user’s password viareset_password_admin.php, a row is inserted into the reset_logs table recording id_admin, id_usuario_afectado, and fecha_reseteo. This provides an immutable audit trail viewable through listar_reset_logs.php (admin-only).