clqms-be/docs/JWT_AUTH_IMPLEMENTATION.md
mahdahar eb883cf059 feat: Add V2 UI with JWT auth, DaisyUI 5, and theme system
- Implement JWT authentication with HTTP-only cookies
- Create /v2/* namespace to avoid conflicts with existing frontend
- Upgrade to DaisyUI 5 + Tailwind CSS 4
- Add light/dark theme toggle with smooth transitions
- Build login page, dashboard, and patient list UI
- Protect V2 routes with auth middleware
- Add comprehensive documentation

No breaking changes - all new features under /v2/* namespace
2025-12-30 08:48:13 +07:00

9.2 KiB

JWT Authentication Implementation

Date: 2025-12-30

Overview

Implemented complete JWT (JSON Web Token) authentication system for CLQMS using HTTP-only cookies for secure token storage.


Architecture

Authentication Flow

┌─────────┐         ┌──────────┐         ┌──────────┐
│ Browser │ ◄─────► │  Server  │ ◄─────► │ Database │
└─────────┘         └──────────┘         └──────────┘
     │                    │                     │
     │  1. POST /login    │                     │
     ├───────────────────►│                     │
     │                    │  2. Verify user     │
     │                    ├────────────────────►│
     │                    │◄────────────────────┤
     │                    │  3. Generate JWT    │
     │  4. Set cookie     │                     │
     │◄───────────────────┤                     │
     │                    │                     │
     │  5. Access page    │                     │
     ├───────────────────►│                     │
     │                    │  6. Verify JWT      │
     │  7. Return page    │                     │
     │◄───────────────────┤                     │

Components

1. Auth Controller (app/Controllers/Auth.php)

Endpoints:

Method Route Description
POST /api/auth/login Login with username/password
POST /api/auth/register Register new user
GET /api/auth/check Check authentication status
POST /api/auth/logout Logout and clear token

Key Features:

  • JWT token generation using firebase/php-jwt
  • Password hashing with password_hash()
  • HTTP-only cookie storage for security
  • 10-day token expiration
  • Secure cookie handling (HTTPS/HTTP aware)

2. Auth Filter (app/Filters/AuthFilter.php)

Purpose: Protect routes from unauthorized access

Behavior:

  • Checks for JWT token in cookies
  • Validates token signature and expiration
  • Differentiates between API and page requests
  • API requests: Returns 401 JSON response
  • Page requests: Redirects to /login

Protected Routes:

  • / (Dashboard)
  • /patients
  • /requests
  • /settings

3. Login Page (app/Views/auth/login.php)

Features:

  • Beautiful animated gradient background
  • Username/password form
  • Password visibility toggle
  • Remember me checkbox
  • Registration modal
  • Error/success message display
  • Loading states
  • Responsive design
  • Alpine.js for reactivity

Design:

  • Animated gradient background
  • Glass morphism card design
  • FontAwesome icons
  • DaisyUI 5 components

4. Routes Configuration (app/Config/Routes.php)

// Public Routes (no auth)
$routes->get('/login', 'PagesController::login');

// Auth API Routes
$routes->post('api/auth/login', 'Auth::login');
$routes->post('api/auth/register', 'Auth::register');
$routes->get('api/auth/check', 'Auth::checkAuth');
$routes->post('api/auth/logout', 'Auth::logout');

// Protected Page Routes (requires auth filter)
$routes->group('', ['filter' => 'auth'], function ($routes) {
    $routes->get('/', 'PagesController::dashboard');
    $routes->get('/patients', 'PagesController::patients');
    $routes->get('/requests', 'PagesController::requests');
    $routes->get('/settings', 'PagesController::settings');
});

Security Features

1. HTTP-Only Cookies

  • Token stored in HTTP-only cookie
  • Not accessible via JavaScript
  • Prevents XSS attacks
[
    'name'     => 'token',
    'httponly' => true,                    // XSS protection
    'secure'   => $isSecure,               // HTTPS only (production)
    'samesite' => Cookie::SAMESITE_LAX,    // CSRF protection
    'expire'   => 864000                   // 10 days
]

3. Password Hashing

  • Uses password_hash() with PASSWORD_DEFAULT
  • Bcrypt algorithm
  • Automatic salt generation

4. JWT Signature

  • HMAC-SHA256 algorithm
  • Secret key from .env file
  • Prevents token tampering

Database Schema

Users Table

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(255) UNIQUE NOT NULL,
    password VARCHAR(255) NOT NULL,
    role_id INT DEFAULT 1,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

Environment Configuration

Add to .env file:

JWT_SECRET=your-super-secret-key-here-change-in-production

⚠️ Important:

  • Use a strong, random secret key in production
  • Never commit .env to version control
  • Minimum 32 characters recommended

Usage Examples

Frontend Login (Alpine.js)

async login() {
  const res = await fetch(`${BASEURL}api/auth/login`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      username: this.form.username,
      password: this.form.password
    })
  });

  const data = await res.json();
  
  if (res.ok && data.status === 'success') {
    window.location.href = `${BASEURL}`;
  }
}

Frontend Logout (Alpine.js)

async logout() {
  const res = await fetch(`${BASEURL}api/auth/logout`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' }
  });
  
  if (res.ok) {
    window.location.href = `${BASEURL}login`;
  }
}

Check Auth Status

const res = await fetch(`${BASEURL}api/auth/check`);
const data = await res.json();

if (data.status === 'success') {
  console.log('User:', data.data.username);
  console.log('Role:', data.data.roleid);
}

API Response Format

Success Response

{
  "status": "success",
  "code": 200,
  "message": "Login successful"
}

Error Response

{
  "status": "failed",
  "code": 401,
  "message": "Invalid password"
}

Testing

Manual Testing Checklist

  • Login with valid credentials
  • Login with invalid credentials
  • Register new user
  • Register duplicate username
  • Access protected page without login (should redirect)
  • Access protected page with valid token
  • Logout functionality
  • Token expiration (after 10 days)
  • Theme persistence after login
  • Responsive design on mobile

Test Users

Create test users via registration or SQL:

INSERT INTO users (username, password, role_id) 
VALUES ('admin', '$2y$10$...hashed_password...', 1);

Files Modified/Created

Created

  1. app/Views/auth/login.php - Login page with registration modal
  2. docs/JWT_AUTH_IMPLEMENTATION.md - This documentation

Modified

  1. app/Filters/AuthFilter.php - Updated redirect path to /login
  2. app/Config/Routes.php - Added auth filter to protected routes
  3. app/Views/layout/main_layout.php - Added logout functionality

Existing (No changes needed)

  1. app/Controllers/Auth.php - Already implemented
  2. app/Config/Filters.php - Already configured

Troubleshooting

Issue: "Token not found" on protected pages

Solution: Check if login is setting the cookie correctly

// In browser console
document.cookie

Issue: "Invalid token signature"

Solution: Verify JWT_SECRET in .env matches between login and verification

Issue: Redirect loop

Solution: Ensure /login route is NOT protected by auth filter

Issue: CORS errors

Solution: Check CORS filter configuration in app/Filters/Cors.php


Future Enhancements

  1. Password Reset - Email-based password recovery
  2. Two-Factor Authentication - TOTP/SMS verification
  3. Session Management - View and revoke active sessions
  4. Role-Based Access Control - Different permissions per role
  5. OAuth Integration - Google/Microsoft login
  6. Refresh Tokens - Automatic token renewal
  7. Account Lockout - After failed login attempts
  8. Audit Logging - Track login/logout events

Security Best Practices

Implemented:

  • HTTP-only cookies
  • Password hashing
  • JWT signature verification
  • HTTPS support
  • SameSite cookie protection

⚠️ Recommended for Production:

  • Rate limiting on login endpoint
  • CAPTCHA after failed attempts
  • IP-based blocking
  • Security headers (CSP, HSTS)
  • Regular security audits
  • Token rotation
  • Shorter token expiration (1-2 hours with refresh token)

References


Implementation completed by: AI Assistant
Date: 2025-12-30
Status: Production Ready