| Server IP : 65.108.144.40 / Your IP : 216.73.217.165 Web Server : Apache/2.4.52 (Ubuntu) System : Linux ubuntu-8gb-hel1-1 5.15.0-173-generic #183-Ubuntu SMP Fri Mar 6 13:29:34 UTC 2026 x86_64 User : dev ( 1000) PHP Version : 8.2.30 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /var/www/html/project-slim/ |
Upload File : |
# Authentication Flow Documentation
## Overview
This document outlines the complete authentication flow for the Slim Framework 4 API, detailing how data is processed through each step from initial request to final response.
## Table of Contents
1. [System Architecture](#system-architecture)
2. [Authentication Endpoints](#authentication-endpoints)
3. [Registration Flow](#registration-flow)
4. [Login Flow](#login-flow)
5. [Token Management](#token-management)
6. [Middleware Protection](#middleware-protection)
7. [Password Management](#password-management)
8. [Data Flow Diagrams](#data-flow-diagrams)
9. [Error Handling](#error-handling)
10. [Security Features](#security-features)
## System Architecture
### Core Components
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Client App │───▶│ Slim Router │───▶│ AuthController │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ JWT Response │◀───│ AuthService │───▶│ AuthValidator │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ UserRepository │ │ BaseValidator │
└─────────────────┘ └─────────────────┘
│
▼
┌─────────────────┐
│ Database │
└─────────────────┘
```
### File Structure
```
app/
├── Controllers/
│ └── AuthController.php # HTTP request handling and response
├── Services/
│ └── AuthService.php # Business logic and JWT management
├── Validators/
│ ├── BaseValidator.php # Core validation framework
│ └── AuthValidator.php # Authentication-specific validation
├── Middleware/
│ └── AuthMiddleware.php # JWT token verification
├── Routes/Groups/
│ └── AuthGroup.php # Authentication route definitions
└── Exceptions/
└── ValidationException.php # Custom validation exception handling
```
## Authentication Endpoints
### Public Endpoints (No Authentication Required)
| Method | Endpoint | Purpose |
|--------|----------|---------|
| POST | `/auth/login` | User authentication |
| POST | `/auth/register` | User registration |
| POST | `/auth/refresh` | Token refresh |
| POST | `/auth/forgot-password` | Password reset request |
| POST | `/auth/reset-password` | Password reset with token |
| GET | `/auth/verify-email/{token}` | Email verification |
| POST | `/auth/resend-verification` | Resend verification email |
### Protected Endpoints (Authentication Required)
| Method | Endpoint | Purpose |
|--------|----------|---------|
| POST | `/auth/logout` | User logout |
| POST | `/auth/change-password` | Password change |
| GET | `/auth/check` | Authentication status |
| POST | `/auth/2fa/setup` | Two-factor authentication setup |
| POST | `/auth/2fa/verify` | Two-factor authentication verification |
| POST | `/auth/2fa/disable` | Disable two-factor authentication |
| GET | `/auth/sessions` | Get active sessions |
| DELETE | `/auth/sessions/all` | Revoke all sessions |
| DELETE | `/auth/sessions/{id}` | Revoke specific session |
| GET | `/auth/profile` | Get user profile |
| PUT | `/auth/profile` | Update user profile |
## Registration Flow
### Step-by-Step Process
#### 1. HTTP Request Reception
```
POST /auth/register
Content-Type: application/json
{
"first_name": "John",
"last_name": "Doe",
"email": "john.doe@example.com",
"password": "SecurePass123!",
"phone": "+1234567890",
"company_id": 1
}
```
#### 2. Route Processing
- **File**: `app/Routes/Groups/AuthGroup.php`
- **Action**: Router matches `/auth/register` to `AuthController::register`
- **Method**: POST request routed to controller
#### 3. Controller Layer (`AuthController::register`)
```php
public function register(Request $request, Response $response): Response
{
try {
// Extract request data
$data = $request->getParsedBody();
// Call service layer
$user = $this->authService->register($data);
// Return success response
return $this->successResponse($response, $user, 'Registration successful', 201);
} catch (\Exception $e) {
return $this->handleException($response, $e);
}
}
```
#### 4. Service Layer (`AuthService::register`)
```php
public function register(array $data): array
{
// 1. Validate input data
$this->authValidator->validateRegister($data);
// 2. Check for existing email
$existingUser = $this->userRepo->findByEmail($data['email']);
if ($existingUser) {
throw new ValidationException("Email already exists",
['email' => 'This email is already registered']);
}
// 3. Hash password
$data['password'] = $this->hashPassword($data['password']);
// 4. Create user record
$user = $this->userRepo->create($data);
// 5. Generate verification token
$verificationToken = $this->generateVerificationToken($user);
return [
'user' => $user->toArray(),
'message' => 'User registered successfully. Please verify your email.',
'verification_token' => $verificationToken
];
}
```
#### 5. Validation Layer (`AuthValidator::validateRegister`)
**Comprehensive Validation Rules:**
```php
public function validateRegister(array $data): void
{
$this->data = $data;
$this->clearErrors();
// Name validation
$this->required('first_name', 'First name is required')
->minLength('first_name', 2, 'First name must be at least 2 characters')
->maxLength('first_name', 50, 'First name must not exceed 50 characters')
->regex('first_name', '/^[a-zA-Z\s\-\'\.]+$/', 'Invalid characters in first name');
$this->required('last_name', 'Last name is required')
->minLength('last_name', 2, 'Last name must be at least 2 characters')
->maxLength('last_name', 50, 'Last name must not exceed 50 characters')
->regex('last_name', '/^[a-zA-Z\s\-\'\.]+$/', 'Invalid characters in last name');
// Email validation
$this->required('email', 'Email address is required')
->email('email', 'Please enter a valid email address')
->maxLength('email', 255, 'Email address too long');
// Strong password validation
$this->required('password', 'Password is required')
->strongPassword('password');
// Optional phone validation
if (isset($data['phone']) && !empty($data['phone'])) {
$this->phone('phone', 'Please enter a valid phone number');
}
// Company ID validation
if (isset($data['company_id'])) {
$this->integer('company_id', 'Company ID must be a valid integer')
->min('company_id', 1, 'Company ID must be positive');
}
$this->throwIfErrors('Registration validation failed');
}
```
**Strong Password Requirements:**
- Minimum 8 characters
- At least one uppercase letter
- At least one lowercase letter
- At least one number
- At least one special character (!@#$%^&*()_+-=[]{}|;:,.<>?)
#### 6. Repository Layer
- **Action**: User data inserted into database
- **Validation**: Database constraints applied
- **Result**: User entity returned with auto-generated ID
#### 7. Response Generation
```json
{
"status": "success",
"message": "Registration successful",
"data": {
"user": {
"id": 123,
"first_name": "John",
"last_name": "Doe",
"email": "john.doe@example.com",
"phone": "+1234567890",
"company_id": 1,
"created_at": "2025-09-15T10:30:00Z",
"updated_at": "2025-09-15T10:30:00Z"
},
"message": "User registered successfully. Please verify your email.",
"verification_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
}
}
```
## Login Flow
### Step-by-Step Process
#### 1. HTTP Request Reception
```
POST /auth/login
Content-Type: application/json
{
"email": "john.doe@example.com",
"password": "SecurePass123!"
}
```
#### 2. Route Processing
- **File**: `app/Routes/Groups/AuthGroup.php`
- **Action**: Router matches `/auth/login` to `AuthController::login`
#### 3. Controller Layer (`AuthController::login`)
```php
public function login(Request $request, Response $response): Response
{
try {
$data = $request->getParsedBody();
// Basic validation
if (!isset($data['email']) || !isset($data['password'])) {
return $this->validationErrorResponse($response, [
'email' => 'Email is required',
'password' => 'Password is required'
]);
}
// Process login
$result = $this->authService->login($data['email'], $data['password']);
if (!$result) {
return $this->unauthorizedResponse($response, 'Invalid credentials');
}
return $this->successResponse($response, $result, 'Login successful');
} catch (\Exception $e) {
return $this->handleException($response, $e);
}
}
```
#### 4. Service Layer (`AuthService::login`)
```php
public function login(string $email, string $password): array
{
// 1. Validate login data
$this->authValidator->validateLogin(['email' => $email, 'password' => $password]);
// 2. Find user by email
$user = $this->userRepo->findByEmail($email);
// 3. Verify credentials
if (!$user || !$this->verifyPassword($password, $user->password_hash)) {
throw new UnauthorizedException("Invalid credentials");
}
// 4. Check account status
if (!$user->isActive()) {
throw new UnauthorizedException("Account is not active");
}
// 5. Generate JWT tokens
$tokens = $this->generateTokens($user);
return [
'access_token' => $tokens['access_token'],
'refresh_token' => $tokens['refresh_token'],
'token_type' => 'Bearer',
'expires_in' => $this->jwtConfig['expiry'],
'user' => $user->toArray()
];
}
```
#### 5. Password Verification Process
```php
private function verifyPassword(string $password, string $hash): bool
{
return password_verify($password, $hash);
}
```
#### 6. JWT Token Generation
```php
private function generateTokens($user): array
{
$now = time();
$expiry = $now + $this->jwtConfig['expiry'];
// Access token payload
$accessPayload = [
'iss' => $this->jwtConfig['issuer'],
'sub' => $user->id,
'iat' => $now,
'exp' => $expiry,
'type' => 'access',
'user_id' => $user->id,
'email' => $user->email,
'role' => $user->role
];
// Refresh token payload (longer expiry)
$refreshPayload = [
'iss' => $this->jwtConfig['issuer'],
'sub' => $user->id,
'iat' => $now,
'exp' => $now + ($this->jwtConfig['expiry'] * 7), // 7x longer
'type' => 'refresh',
'user_id' => $user->id
];
return [
'access_token' => JWT::encode($accessPayload, $this->jwtConfig['secret'], $this->jwtConfig['algorithm']),
'refresh_token' => JWT::encode($refreshPayload, $this->jwtConfig['secret'], $this->jwtConfig['algorithm'])
];
}
```
#### 7. Successful Login Response
```json
{
"status": "success",
"message": "Login successful",
"data": {
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"user": {
"id": 123,
"first_name": "John",
"last_name": "Doe",
"email": "john.doe@example.com",
"role": "user",
"is_active": true
}
}
}
```
## Token Management
### Access Token Structure
```json
{
"iss": "your-app.com",
"sub": "123",
"iat": 1694776800,
"exp": 1694780400,
"type": "access",
"user_id": 123,
"email": "john.doe@example.com",
"role": "user"
}
```
### Refresh Token Structure
```json
{
"iss": "your-app.com",
"sub": "123",
"iat": 1694776800,
"exp": 1695381600,
"type": "refresh",
"user_id": 123
}
```
### Token Refresh Flow
#### 1. Refresh Request
```
POST /auth/refresh
Content-Type: application/json
{
"refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
}
```
#### 2. Token Validation and Refresh
```php
public function refreshToken(string $refreshToken): array
{
try {
// Decode and validate refresh token
$decoded = JWT::decode($refreshToken, new Key($this->jwtConfig['secret'], $this->jwtConfig['algorithm']));
// Verify token type
if ($decoded->type !== 'refresh') {
throw new UnauthorizedException("Invalid refresh token");
}
// Verify user still exists and is active
$user = $this->userRepo->findById($decoded->user_id);
if (!$user || !$user->isActive()) {
throw new UnauthorizedException("User not found or inactive");
}
// Generate new token pair
$tokens = $this->generateTokens($user);
return [
'access_token' => $tokens['access_token'],
'refresh_token' => $tokens['refresh_token'],
'token_type' => 'Bearer',
'expires_in' => $this->jwtConfig['expiry']
];
} catch (\Exception $e) {
throw new UnauthorizedException("Invalid refresh token");
}
}
```
## Middleware Protection
### AuthMiddleware Flow
#### 1. Request Interception
```php
public function __invoke(Request $request, RequestHandler $handler): Response
{
// Extract Authorization header
$authHeader = $request->getHeaderLine('Authorization');
if (empty($authHeader)) {
return $this->unauthorizedResponse('Authorization header required');
}
// Validate Bearer format
if (!preg_match('/Bearer\s+(.*)$/i', $authHeader, $matches)) {
return $this->unauthorizedResponse('Invalid authorization header format');
}
$token = $matches[1];
try {
// Decode JWT token
$decoded = JWT::decode($token, new Key($this->jwtConfig['secret'], $this->jwtConfig['algorithm']));
// Verify token type
if ($decoded->type !== 'access') {
throw new \Exception('Invalid token type');
}
// Add user info to request attributes
$request = $request->withAttribute('user_id', $decoded->user_id);
$request = $request->withAttribute('user_email', $decoded->email);
$request = $request->withAttribute('user_role', $decoded->role);
// Continue to next middleware/controller
return $handler->handle($request);
} catch (\Exception $e) {
return $this->unauthorizedResponse('Invalid or expired token');
}
}
```
#### 2. Protected Endpoint Access
```php
// In protected controller methods
public function getProfile(Request $request, Response $response): Response
{
// Get user ID from middleware
$userId = $request->getAttribute('user_id');
// Fetch user data
$user = $this->userService->getUserById($userId);
return $this->successResponse($response, $user);
}
```
## Password Management
### Forgot Password Flow
#### 1. Request Reset
```
POST /auth/forgot-password
Content-Type: application/json
{
"email": "john.doe@example.com"
}
```
#### 2. Generate Reset Token
```php
public function forgotPassword(string $email): array
{
$user = $this->userRepo->findByEmail($email);
if (!$user) {
// Return success even if user not found (security)
return ['message' => 'If the email exists, a reset link has been sent'];
}
// Generate secure reset token
$resetToken = $this->generatePasswordResetToken($user);
// Store token with expiry (typically 1 hour)
$this->storePasswordResetToken($user->id, $resetToken);
// Send email (in real implementation)
// $this->emailService->sendPasswordResetEmail($user, $resetToken);
return [
'message' => 'Password reset instructions sent to your email',
'reset_token' => $resetToken // Remove in production
];
}
```
#### 3. Reset Password
```
POST /auth/reset-password
Content-Type: application/json
{
"token": "secure_reset_token_here",
"password": "NewSecurePass123!",
"password_confirmation": "NewSecurePass123!"
}
```
```php
public function resetPassword(array $data): array
{
// Validate reset data
$this->authValidator->validatePasswordReset($data);
// Verify reset token
$userId = $this->verifyPasswordResetToken($data['token']);
if (!$userId) {
throw new ValidationException("Invalid or expired reset token");
}
// Hash new password
$hashedPassword = $this->hashPassword($data['password']);
// Update user password
$this->userRepo->updatePassword($userId, $hashedPassword);
// Invalidate reset token
$this->invalidatePasswordResetToken($data['token']);
return ['message' => 'Password reset successfully'];
}
```
## Data Flow Diagrams
### Registration Data Flow
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Client │───▶│ Router │───▶│ Controller │
│ │ │ │ │ │
│ POST /auth/ │ │ Match Route │ │ Extract │
│ register │ │ │ │ Request │
└─────────────┘ └─────────────┘ └─────────────┘
│
▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Database │◀───│ Repository │◀───│ Service │
│ │ │ │ │ │
│ INSERT user │ │ Create User │ │ Business │
│ │ │ │ │ Logic │
└─────────────┘ └─────────────┘ └─────────────┘
▲
│
┌─────────────────┴─────────────┐
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Validator │ │ Hash/Token │
│ │ │ Generation │
│ Validate │ │ │
│ Input │ │ │
└─────────────┘ └─────────────┘
```
### Login Data Flow
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Client │───▶│ Router │───▶│ Controller │
│ │ │ │ │ │
│ POST /auth/ │ │ Match Route │ │ Extract │
│ login │ │ │ │ Credentials │
└─────────────┘ └─────────────┘ └─────────────┘
│
▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ JWT Token │◀───│ Service │───▶│ Validator │
│ Response │ │ │ │ │
│ │ │ Verify │ │ Validate │
│ │ │ Password │ │ Input │
└─────────────┘ └─────────────┘ └─────────────┘
│ ▲
▼ │
┌─────────────┐ ┌─────────────┐
│ Repository │───▶│ Database │
│ │ │ │
│ Find User │ │ SELECT user │
│ by Email │ │ by email │
└─────────────┘ └─────────────┘
```
### Protected Route Access Flow
```
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Client │───▶│ Router │───▶│ Middleware │
│ │ │ │ │ │
│ GET /auth/ │ │ Match Route │ │ Extract & │
│ profile │ │ │ │ Verify JWT │
│ │ │ │ │ Token │
└─────────────┘ └─────────────┘ └─────────────┘
│
┌────────┴────────┐
│ Valid Token? │
└────────┬────────┘
Yes │ No
┌──────────────┼───────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Controller │ │ 401 Error │ │ Return │
│ │ │ Response │ │ Unauthorized│
│ Process │ │ │ │ │
│ Request │ │ │ │ │
└─────────────┘ └─────────────┘ └─────────────┘
```
## Error Handling
### Validation Errors
```json
{
"status": "error",
"message": "Validation failed",
"errors": {
"email": ["Please enter a valid email address"],
"password": ["Password must be at least 8 characters long", "Password must contain at least one uppercase letter"]
}
}
```
### Authentication Errors
```json
{
"status": "error",
"message": "Invalid credentials",
"code": 401
}
```
### Authorization Errors
```json
{
"status": "error",
"message": "Access denied. Insufficient permissions",
"code": 403
}
```
### Token Errors
```json
{
"status": "error",
"message": "Invalid or expired token",
"code": 401
}
```
## Security Features
### Password Security
- **Hashing**: bcrypt with automatic salt generation
- **Strength Requirements**: Enforced through validation
- **Password History**: Prevent reuse of recent passwords (future enhancement)
### JWT Security
- **Algorithm**: HMAC SHA-256 (HS256)
- **Secret Key**: Environment-specific secret
- **Token Expiry**: Short-lived access tokens (1 hour)
- **Refresh Tokens**: Longer-lived for token renewal (7 days)
### Request Security
- **Rate Limiting**: Prevent brute force attacks (future enhancement)
- **CORS**: Configured for specific origins
- **HTTPS**: Enforced in production
- **Input Sanitization**: Comprehensive validation
### Session Security
- **Token Blacklisting**: Logout invalidates tokens (future enhancement)
- **Session Management**: Track and manage active sessions
- **Concurrent Sessions**: Limit simultaneous logins (configurable)
## Configuration
### Environment Variables
```env
# JWT Configuration
JWT_SECRET=your_super_secure_secret_key_here
JWT_ISSUER=your-app.com
JWT_EXPIRY=3600
# Database Configuration
DB_HOST=localhost
DB_NAME=your_database
DB_USER=your_username
DB_PASS=your_password
# Email Configuration (for verification/reset)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your_email@gmail.com
SMTP_PASS=your_password
```
### Security Headers
```php
// Add to middleware or global configuration
$response = $response
->withHeader('X-Content-Type-Options', 'nosniff')
->withHeader('X-Frame-Options', 'DENY')
->withHeader('X-XSS-Protection', '1; mode=block')
->withHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
```
This documentation provides a comprehensive overview of the authentication system architecture, data flow, and security implementation. The system follows industry best practices for secure authentication and authorization in modern web applications.