Overview
MediGuide provides a comprehensive authentication system that handles user registration, login, and password recovery. The system stores user credentials securely and maintains session state using localStorage.
User Registration (Signup)
API Endpoint
POST / api / users / signup
Content - Type : application / json
Request Body
{
"username" : "string" ,
"email" : "string" ,
"password" : "string"
}
Email Validation
The system validates email format using a regex pattern:
const emailRegex = / ^ [ ^ \s@ ] + @ [ ^ \s@ ] + \. [ ^ \s@ ] + $ / ;
if ( ! emailRegex . test ( formData . email )) {
setMessage ( 'Por favor ingresa un correo electrónico válido' );
return ;
}
Password Confirmation
During signup, users must confirm their password. The system validates that both passwords match:
if ( formData . password !== formData . confirmPassword ) {
setMessage ( 'Las contraseñas no coinciden' );
return ;
}
Username Field
Email Field
Password Field
Confirm Password Field
< input
type = 'text'
name = 'username'
value = { formData . username }
onChange = { handleChange }
required
placeholder = 'Ingresa tu nombre de usuario'
/>
Success Response
{
"message" : "User registered successfully" ,
"userId" : 123 ,
"username" : "johndoe"
}
Error Responses
Duplicate User/Email (400)
{
"error" : "Usuario ya está registrado"
}
// or
{
"error" : "Correo ya está registrado"
}
Invalid Email Format (Client-side)
Password Mismatch (Client-side)
Message: "Las contraseñas no coinciden"
Client-Side Implementation
const response = await fetch ( ` ${ apiUrl } /api/users/signup` , {
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ({
username: formData . username ,
email: formData . email ,
password: formData . password
})
});
const data = await response . json ();
if ( response . ok ) {
localStorage . setItem ( 'userId' , data . userId );
localStorage . setItem ( 'username' , data . username );
// Redirect to main app
onAuthSuccess ();
}
User Login
API Endpoint
POST / api / users / login
Content - Type : application / json
Request Body
{
"username" : "string" ,
"password" : "string"
}
Login Implementation
const response = await fetch ( ` ${ apiUrl } /api/users/login` , {
method: 'POST' ,
headers: {
'Content-Type' : 'application/json' ,
},
body: JSON . stringify ({
username: formData . username ,
password: formData . password
})
});
const data = await response . json ();
if ( response . ok ) {
localStorage . setItem ( 'userId' , data . userId );
localStorage . setItem ( 'username' , data . username );
onAuthSuccess ();
}
Success Response
{
"message" : "Login successful" ,
"userId" : 123 ,
"username" : "johndoe"
}
Error Response
{
"error" : "Usuario o contraseña incorrectos"
}
Password Reset Flow
The password reset process involves three steps:
Step 1: Request Reset Code
Endpoint: POST /api/users/forgot-password
{
"message" : "Reset code sent to email" ,
"resetCode" : "123456"
}
The reset code is a 6-digit numeric code that expires after 30 minutes.
Step 2: Verify Reset Code
Endpoint: POST /api/users/verify-reset-code
{
"message" : "Reset code verified" ,
"userId" : 123
}
Error Responses:
{
"error" : "Código de recuperación inválido"
}
Step 3: Reset Password
Endpoint: POST /api/users/reset-password
{
"email" : "[email protected] " ,
"resetCode" : "123456" ,
"newPassword" : "newSecurePassword123"
}
{
"message" : "Contraseña actualizada exitosamente" ,
"userId" : 123 ,
"username" : "johndoe"
}
Passwords must be at least 6 characters long. Shorter passwords will be rejected with a 400 error.
Security Features
Password Visibility Toggle
Both password fields include show/hide functionality:
const [ showPassword , setShowPassword ] = useState ( false );
const [ showConfirmPassword , setShowConfirmPassword ] = useState ( false );
// Toggle button implementation
< button
type = 'button'
onClick = { () => setShowPassword ( ! showPassword ) }
>
{ showPassword ? 'Ocultar' : 'Mostrar' }
</ button >
Session Management
User sessions are maintained using localStorage:
// Store user session
localStorage . setItem ( 'userId' , data . userId );
localStorage . setItem ( 'username' , data . username );
// Retrieve current user
const userId = localStorage . getItem ( 'userId' );
const username = localStorage . getItem ( 'username' );
Database Schema
CREATE TABLE users (
id SERIAL PRIMARY KEY ,
username VARCHAR UNIQUE NOT NULL ,
email VARCHAR UNIQUE NOT NULL ,
password VARCHAR NOT NULL ,
reset_code VARCHAR ,
reset_code_expiry TIMESTAMP ,
created_at TIMESTAMP DEFAULT NOW ()
);
The authentication form uses React state to manage user input:
const [ formData , setFormData ] = useState ({
username: '' ,
email: '' ,
password: '' ,
confirmPassword: ''
});
const handleChange = ( e ) => {
const { name , value } = e . target ;
setFormData ( prev => ({
... prev ,
[name]: value
}));
};
Loading States
The system provides visual feedback during API calls:
const [ loading , setLoading ] = useState ( false );
// During form submission
setLoading ( true );
// Button disabled during loading
< button
type = 'submit'
disabled = { loading }
style = { {
backgroundColor: loading ? '#ccc' : '#0066cc'
} }
>
{ loading ? 'Cargando...' : ( isLogin ? 'Iniciar Sesión' : 'Registrarse' ) }
</ button >
Error Handling
Comprehensive error handling with user-friendly messages:
try {
const response = await fetch ( apiUrl , options );
const data = await response . json ();
if ( response . ok ) {
setMessage ( '¡Cuenta creada exitosamente!' );
} else {
setMessage ( `Error: ${ data . error } ` );
}
} catch ( error ) {
setMessage ( `Error de conexión: ${ error . message } ` );
}
UI Components
Mode Toggle
Switch between login and signup modes:
const [ isLogin , setIsLogin ] = useState ( true );
const toggleMode = () => {
setIsLogin ( ! isLogin );
setFormData ({
username: '' ,
email: '' ,
password: '' ,
confirmPassword: ''
});
setMessage ( '' );
};
Message Display
Dynamic message styling based on success/error:
{ message && (
< p style = { {
color: ( message . includes ( 'Error' ) ||
message . includes ( 'no coinciden' ) ||
message . includes ( 'válido' )) ? '#d32f2f' : '#4CAF50' ,
backgroundColor: ( message . includes ( 'Error' ) ||
message . includes ( 'no coinciden' ) ||
message . includes ( 'válido' )) ? '#ffebee' : '#e8f5e9'
} } >
{ message }
</ p >
)}
API Base URL
The authentication system connects to the backend API:
const apiUrl = 'http://localhost:3001' ;
Ensure the backend server is running on port 3001 before attempting authentication operations.
Session Management
User Session Storage
After successful authentication, user session data is stored in the browser’s localStorage:
// Stored after login/signup
localStorage . setItem ( 'userId' , data . userId );
localStorage . setItem ( 'username' , data . username );
// Retrieved on app load
const userId = localStorage . getItem ( 'userId' );
const username = localStorage . getItem ( 'username' );
Session Persistence
The application checks for existing sessions on page load:
useEffect (() => {
const userId = localStorage . getItem ( 'userId' );
if ( userId ) {
setIsAuthenticated ( true );
}
}, []);
This allows users to remain logged in across browser sessions until they explicitly log out.
Logout Functionality
User Interface
The logout button appears in the application header after successful authentication:
Location : Top-right corner of the header
Label : “Cerrar Sesión” (Close Session)
Visibility : Only shown when user is authenticated
Logout Implementation
The logout process from header.jsx:4-27:
function HeaderContent ({ onLogout }){
const username = localStorage . getItem ( 'username' );
return (
< header >
< img src = { logo } alt = 'Mediguide Logo' ></ img >
< p > Donde la salud del usuario es nuestra prioridad </ p >
{ username && (
< div className = "header-user-section" >
< span className = "welcome-text" > Bienvenido, { username } </ span >
< button
type = 'button'
onClick = { onLogout }
className = "logout-button"
>
Cerrar Sesión
</ button >
</ div >
) }
</ header >
)
}
Logout Handler
From App.jsx:28-32:
const handleLogout = () => {
localStorage . removeItem ( 'userId' );
localStorage . removeItem ( 'username' );
setIsAuthenticated ( false );
};
Logout Process
Click Logout Button
User clicks Cerrar Sesión button in the header
Clear Session Data
Application removes userId and username from localStorage
Update Authentication State
Authentication state is set to false
Redirect to Login
User is automatically redirected to the login/signup page
Security Considerations
Session Timeout : The current implementation does not include automatic session expiration. Sessions persist until the user explicitly logs out or clears browser data.
Shared Devices : Always log out when using shared or public devices to protect your medical data. Simply closing the browser does NOT log you out.
Password Recovery Reset your password if you forget it
Creating Account Complete signup guide
Contact Support Get help with account issues
API Authentication Developer authentication documentation