# Forgot Password Feature - Complete Implementation

## Overview
This document details the unified "Forgot Password" feature implemented for all portals (Client, Agent, Lawyer, Admin). Users can now reset their password using email verification with OTP.

## Flow Diagram

```
User clicks "Forgot Password?" on login page
        ↓
Step 1: Enter Email Address
    → System checks if email exists in database
    → If exists: Send OTP to email (valid for 15 minutes)
    → If not exists: Show error "No account found"
        ↓
Step 2: Verify OTP
    → User receives email with 6-digit OTP
    → User enters OTP on verification page
    → System validates OTP
        ↓
Step 3: Reset Password
    → User enters new password (min 8 characters)
    → User confirms password match
    → System updates password in database
    → Redirects to login with success message
        ↓
User logs in with new password
```

## Files Created

### Controllers
- **`app/Http/Controllers/Auth/ForgotPasswordController.php`**
  - `showForgotForm()` - Show email entry form
  - `sendOtp()` - Generate and send OTP to email
  - `showOtpForm()` - Show OTP verification form
  - `verifyOtp()` - Verify OTP code
  - `showResetForm()` - Show password reset form
  - `resetPassword()` - Update password and complete reset

### Models
- **`app/Models/PasswordResetOtp.php`**
  - Stores OTP records with expiration
  - Tracks email and user ID
  - Methods: `isValid()`, `markAsVerified()`

### Mail Classes
- **`app/Mail/ForgotPasswordOtpMail.php`**
  - Sends OTP email with proper from/reply-to headers
  - Includes security instructions

### Views
- **`resources/views/auth/forgot-password.blade.php`**
  - Step 1: Email entry form
  - Shows instructions on how it works

- **`resources/views/auth/verify-forgot-otp.blade.php`**
  - Step 2: OTP verification form
  - Displays user's email for confirmation
  - Shows expiration time

- **`resources/views/auth/reset-forgot-password.blade.php`**
  - Step 3: New password entry
  - Real-time password match validation
  - Password strength indicator
  - Shows requirements

- **`resources/views/emails/forgot-password-otp.blade.php`**
  - Email template sent to user
  - Displays 6-digit OTP in large format
  - Instructions on how to proceed
  - Security warnings

### Database
- **`database/migrations/2026_07_09_create_password_reset_otps_table.php`**
  - Creates `password_reset_otps` table
  - Columns: id, user_id, email, otp_code, expires_at, verified_at, timestamps

### Routes
Added to `routes/web.php`:
```php
Route::get('/password/forgot', [ForgotPasswordController::class, 'showForgotForm'])->name('password.request');
Route::post('/password/send-otp', [ForgotPasswordController::class, 'sendOtp'])->name('password.send-otp');
Route::get('/password/verify-otp', [ForgotPasswordController::class, 'showOtpForm'])->name('password.verify-otp');
Route::post('/password/verify-otp', [ForgotPasswordController::class, 'verifyOtp']);
Route::get('/password/reset', [ForgotPasswordController::class, 'showResetForm'])->name('password.reset');
Route::post('/password/reset', [ForgotPasswordController::class, 'resetPassword'])->name('password.update');
```

## URLs

| Step | Method | URL | Name |
|------|--------|-----|------|
| 1 | GET | `/password/forgot` | `password.request` |
| 1 | POST | `/password/send-otp` | `password.send-otp` |
| 2 | GET | `/password/verify-otp?email=...` | `password.verify-otp` |
| 2 | POST | `/password/verify-otp` | (same) |
| 3 | GET | `/password/reset?token=...&email=...` | `password.reset` |
| 3 | POST | `/password/reset` | `password.update` |

## Features

✅ **Email Validation**
- Checks if email exists in system
- Shows appropriate error if not found

✅ **OTP Generation & Sending**
- 6-digit random OTP generated
- Valid for 15 minutes
- Sent via email with proper sender info
- Fixed SPF/DKIM from previous OTP fix

✅ **Security**
- OTP expires after 15 minutes
- Expired OTPs cleaned up automatically
- One-time use only (deleted after successful reset)
- Token-based reset validation

✅ **Password Requirements**
- Minimum 8 characters
- Real-time match validation
- Visual feedback (✓ Passwords match!)
- Requirements displayed to user

✅ **User Experience**
- Clear step-by-step process
- Helpful instructions and info boxes
- Show which email OTP was sent to
- Back buttons to restart process
- Success messages after each step

✅ **Works for All Portals**
- Single unified forgot password for all roles
- Client, Agent, Lawyer, Admin all use same page
- No role-specific login page changes needed

## Installation

1. **Run migrations** to create password_reset_otps table:
```bash
php artisan migrate
```

2. **Update login page link**:
   - Already done in `resources/views/auth/role-login.blade.php`
   - Link: `{{ route('password.request') }}`

3. **Test the flow**:
   - Go to `http://127.0.0.1:8000/password/forgot`
   - Enter an email that exists in system
   - Check email for OTP
   - Follow the verification flow

## Error Handling

| Scenario | Response |
|----------|----------|
| Email not found | "No account found with this email address" |
| Invalid OTP | "Invalid or expired OTP. Please try again" |
| Expired OTP | "Invalid or expired OTP. Please try again" |
| Password mismatch | "Passwords do not match" |
| Password too short | "Password too short (minimum 8 characters)" |
| Expired reset link | "Invalid or expired reset link" |

## Email Flow

The forgot password email includes:
- Clear subject line: "Password Reset OTP - FWG Trustees"
- Large, easy-to-read OTP code
- Step-by-step instructions
- Expiration warning (15 minutes)
- Security notice: "Never share this OTP"
- Support contact information

## Security Considerations

1. **OTP Security**
   - Random 6-digit code
   - 15-minute expiration
   - One-time use
   - Deleted after successful reset

2. **Token Security**
   - Uses OTP record ID as reset token
   - Verified against email on reset
   - Checks expiration time

3. **Password Security**
   - Passwords hashed with bcrypt
   - 8-character minimum enforced
   - No password hints sent via email

4. **Email Security**
   - SPF/DKIM configured (from OTP fix)
   - From: info@dextratechnologies.com
   - Reply-To: support@fwgtrustees.com

## Logging

All password reset actions logged:
- OTP sent: Email, OTP ID, User ID
- OTP verified: User ID, Email, Edit Request ID
- Password reset: User ID, Email, Success/Failure

Check logs in `storage/logs/laravel.log`

## Testing Scenarios

### Scenario 1: Happy Path
1. Go to forgot password page
2. Enter existing email
3. Check email (or logs if MAIL_MAILER=log)
4. Enter correct OTP
5. Enter matching passwords
6. Redirected to login with success
7. Login with new password works ✓

### Scenario 2: Email Not Found
1. Go to forgot password page
2. Enter non-existent email
3. See error: "No account found with this email address" ✓

### Scenario 3: Invalid OTP
1. Follow steps 1-2 from Scenario 1
2. Enter wrong OTP
3. See error: "Invalid or expired OTP" ✓

### Scenario 4: Expired OTP (after 15 mins)
1. Request OTP
2. Wait 15+ minutes
3. Try to verify OTP
4. See error: "Invalid or expired OTP" ✓

### Scenario 5: Password Mismatch
1. Follow steps 1-4 from Scenario 1
2. Enter different passwords
3. Submit button disabled, cannot proceed ✓

## Frontend Validation

- Email format validation
- OTP: 6 digits only
- Password: minimum 8 characters
- Real-time password match checking
- Visual feedback on form fields

## Backend Validation

- Email must exist in database
- OTP code must be exactly 6 digits
- OTP must not be expired
- Password confirmation must match
- Password minimum length: 8 characters
- CSRF token validation on all POST requests

## Integration with Existing System

- Uses existing `User` model
- Uses existing database connection
- Uses existing mail configuration
- Does NOT break existing password reset (if any)
- Works alongside existing auth system

## Future Enhancements

1. Email delivery rate tracking
2. Password reset history/audit log
3. Rate limiting (max 3 OTP requests per hour)
4. SMS OTP as backup option
5. "Change password" functionality for logged-in users
6. Password expiration policy enforcement

## Troubleshooting

**Problem**: Email not being sent
- Check `.env` MAIL_MAILER settings
- Verify SMTP credentials (GoDaddy)
- Check `storage/logs/laravel.log`
- Use `MAIL_MAILER=log` for testing

**Problem**: OTP shows as invalid
- Check OTP expiration (15 minutes max)
- Verify OTP from email matches entry
- OTP is case-sensitive (if numbers only, not applicable)

**Problem**: Database errors during migration
- Run: `php artisan migrate:fresh` (development only!)
- Or manually create table from migration SQL

**Problem**: Users redirected to wrong page after reset
- Check route names in controller
- Verify `route('login')` exists
- Check middleware configuration

## Maintenance

### Cleanup Expired OTPs
Runs automatically when new OTP requested. To manually clean:
```bash
php artisan tinker
> \App\Models\PasswordResetOtp::where('expires_at', '<', now())->delete();
```

### Monitor Logs
```bash
tail -f storage/logs/laravel.log | grep "OTP\|password"
```

## Support

For issues:
1. Check logs: `storage/logs/laravel.log`
2. Verify database table exists: `password_reset_otps`
3. Check mail configuration in `.env`
4. Review error messages in browser/network tab
