Skip to main content

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;
}

Form Fields

<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

{
  "error": "Usuario ya está registrado"
}
// or
{
  "error": "Correo ya está registrado"
}
Message: "Por favor ingresa un correo electrónico válido"
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
Request
{
  "email": "[email protected]"
}
Response
{
  "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
Request
{
  "email": "[email protected]",
  "resetCode": "123456"
}
Response
{
  "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
Request
{
  "email": "[email protected]",
  "resetCode": "123456",
  "newPassword": "newSecurePassword123"
}
Response
{
  "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()
);

Form State Management

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:
header.jsx
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:
App.jsx
const handleLogout = () => {
  localStorage.removeItem('userId');
  localStorage.removeItem('username');
  setIsAuthenticated(false);
};

Logout Process

1

Click Logout Button

User clicks Cerrar Sesión button in the header
2

Clear Session Data

Application removes userId and username from localStorage
3

Update Authentication State

Authentication state is set to false
4

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

Build docs developers (and LLMs) love