Overview
vLife DGO uses session-based authentication with bcrypt password hashing to secure employee access. The system manages user registration, login, logout, and session verification throughout the application.
Authentication Flow
User Registration
New employees register by providing their complete information, which is validated before account creation.
Password Hashing
Passwords are hashed using bcrypt with 10 salt rounds before storage.
Session Creation
Upon successful login, a server-side session is created with user details.
Access Control
Protected routes verify session validity before granting access.
User Registration
Registration Endpoint
The createUser function handles new user registration with comprehensive validation.
const createUser = async ( req , res ) => {
let {
empNombreCompleto ,
empRFC ,
empUsuario ,
empContrasenia ,
empTipoEval ,
empMotivo ,
empDependencia ,
empSexo
} = req . body ;
try {
// Check if user already exists
const [ rows ] = await PoolvLife . query ( AuthModel . findUser , empUsuario );
if ( rows . length === 0 ) {
// Hash password with bcrypt
const saltRounds = 10 ;
bcrypt . hash (
empContrasenia ,
saltRounds ,
async function ( err , empPassword ) {
const usrData = {
empNombreCompleto ,
empRFC ,
empUsuario ,
empSexo ,
empContrasenia ,
empPassword ,
empTipoEval ,
empMotivo ,
empDependencia ,
};
await PoolvLife . query ( AuthModel . addUser , usrData );
}
);
req . flash ( "success" , "Usuario guardado !" );
res . redirect ( "back" );
} else {
req . flash ( "message" , "Este usuario ya existe !" );
res . redirect ( "back" );
}
} catch ( e ) {
console . log ( e );
}
};
Registration includes evaluation type (Permanencia or Nuevo Ingreso) and dependency information for proper evaluation routing.
Registration Data Fields
Field Description empNombreCompletoEmployee’s full name empRFCTax identification number empUsuarioUnique username for login empContraseniaPlain text password (hashed before storage) empTipoEvalEvaluation type (1=Permanencia, 2=Nuevo Ingreso) empMotivoReason for evaluation empDependenciaGovernment dependency/department empSexoGender
Login Process
User Validation
The userValidator function authenticates users by comparing hashed passwords.
const userValidator = async ( req , res ) => {
const { empUsuario , empContrasenia } = req . body ;
try {
const [ rows ] = await PoolvLife . query ( AuthModel . findUserLogin , empUsuario );
if ( rows . length === 1 ) {
const usrPassword = rows [ 0 ]. empPassword ;
const usrNombre = rows [ 0 ]. empNombreCompleto ;
const usrId = rows [ 0 ]. empID ;
// Compare provided password with stored hash
bcrypt . compare ( empContrasenia , usrPassword , function ( e , result ) {
if ( result ) {
// Create session
req . session . loggedin = true ;
req . session . name = usrNombre ;
req . session . usrId = usrId ;
req . flash ( "success" , `Nuevo inicio de sesión !` );
res . redirect ( "/auth/profile" );
} else {
req . flash ( "message" , "Usuario no valido" );
res . redirect ( "back" );
}
});
} else {
req . flash ( "message" , "Usuario no valido" );
res . redirect ( "back" );
}
} catch ( e ) {
console . log ( e );
}
};
Session Data
Successful authentication stores the following in the session:
req.session.loggedin - Boolean flag indicating authenticated state
req.session.name - Employee’s full name for display
req.session.usrId - Unique user ID for database queries
Session Configuration
The application uses express-session with memory store for session management.
import session from "express-session" ;
const sessionStore = new session . MemoryStore ();
app . use ( cookieParser ( "secret" ));
app . use (
session ({
store: sessionStore ,
saveUninitialized: true ,
resave: true ,
secret: "secret" ,
})
);
The memory store is suitable for development but should be replaced with a persistent store (like Redis) for production deployments.
Protected Routes
Session Verification
Routes check session status before rendering protected content.
const profile = async ( req , res ) => {
try {
const usrId = req . session . usrId ;
const [ rows ] = await PoolvLife . query ( AuthModel . getDataUser , usrId );
const anio = new Date (). getFullYear ();
const [ currentEvaluation ] = await PoolvLife . query (
AuthModel . getLastEvaluation ,
[ anio , usrId ]
);
// Render profile with user data
res . render ( "profile" , {
user: req . session . name ,
empleado: rows [ 0 ],
currentEval: currentEvaluation [ 0 ],
// ... additional data
});
} catch ( e ) {
req . flash ( "message" , "Algo salio mal !" );
res . redirect ( "back" );
}
};
Redirect Logic
Pages redirect based on authentication state:
const signin = async ( req , res ) => {
if ( req . session . loggedin != true ) {
res . render ( "auth/signin" );
} else {
// Already logged in, redirect to profile
res . redirect ( "/auth/profile" );
}
};
The logout process destroys the session completely.
const logout = async ( req , res ) => {
if ( req . session . loggedin == true ) {
req . session . destroy ();
res . redirect ( "/auth/signin" );
} else {
res . redirect ( "/auth/signin" );
}
};
Password Security
Bcrypt Implementation
vLife DGO uses bcrypt for one-way password hashing:
Salt Rounds : 10 (provides good balance of security and performance)
Algorithm : bcrypt automatically handles salt generation and storage
Comparison : Uses bcrypt.compare() for constant-time comparison
Bcrypt is designed to be computationally expensive, making brute-force attacks impractical. The 10 salt rounds provide strong protection while maintaining reasonable performance.
User Profile Data
Authenticated users can access their profile, which displays:
Employee information (name, RFC, dependency)
Current year evaluation status
Evaluation history
Uploaded documents
Comments and feedback
Generated certificates (constancias)
Flash Messages
The system uses connect-flash for user feedback:
// Success message
req . flash ( "success" , "Usuario guardado !" );
// Error message
req . flash ( "message" , "Usuario no valido" );
Messages are automatically rendered in views through global variables:
app . use ( function ( req , res , next ) {
app . locals . success = req . flash ( "success" );
app . locals . message = req . flash ( "message" );
next ();
});
Security Considerations
For production deployment, consider:
Using environment variables for session secrets
Implementing HTTPS for all connections
Adding rate limiting for login attempts
Implementing session timeout
Using a persistent session store (Redis, MongoDB)
Adding CSRF protection
Implementing account lockout after failed attempts
Integration with Evaluations
Authentication is tightly integrated with the evaluation system:
User registration includes evaluation type selection
Session stores usrId for linking evaluations to employees
Profile displays current and historical evaluations
Encrypted evaluation IDs ensure secure access
AuthController.js (src/controllers/AuthController.js:1) - Main authentication logic
AuthModel.js - Database queries for user management
app.js (src/app.js:34) - Session configuration
Next Steps
Evaluation Types Learn about Permanencia and Nuevo Ingreso evaluations
Data Capture Explore the six-section data capture process