# Password Reset Feature - Setup Guide

## Overview
A complete password reset system has been implemented for admin and researcher accounts. This feature allows users to securely reset their passwords via email.

## Features
- ✅ Secure token-based password reset
- ✅ Email verification with absolute URLs
- ✅ Token expiration (1 hour)
- ✅ One-time use tokens
- ✅ Admin and Researcher only (participants cannot reset passwords)
- ✅ CSRF protection
- ✅ Password strength validation (minimum 8 characters)
- ✅ Full domain URLs (e.g., https://truaxcreative.com/user_test/public/reset_password.php?token=...)

## Files Created/Modified

### New Files
1. **`scripts/password_reset_setup.sql`** - Database migration for password_resets table
2. **`public/forgot_password.php`** - Request password reset page
3. **`public/reset_password.php`** - Reset password form page

### Modified Files
1. **`includes/auth.php`** - Added password reset functions with absolute URL support
2. **`includes/helpers.php`** - Added `site_origin()` and `absolute_url()` helper functions
3. **`includes/schema.php`** - Added password_resets to allowed tables
4. **`public/login.php`** - Added "Forgot your password?" link

## Setup Instructions

### Step 1: Run Database Migration
Execute the SQL migration to create the `password_resets` table:

```bash
mysql -u YOUR_USERNAME -p YOUR_DATABASE < scripts/password_reset_setup.sql
```

Or run directly in your database:
```sql
CREATE TABLE IF NOT EXISTS `password_resets` (
  `id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  `user_id` INT UNSIGNED NOT NULL,
  `token` VARCHAR(64) NOT NULL UNIQUE,
  `expires_at` DATETIME NOT NULL,
  `used` TINYINT(1) DEFAULT 0,
  `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  INDEX `idx_token` (`token`),
  INDEX `idx_user_id` (`user_id`),
  INDEX `idx_expires_at` (`expires_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
```

### Step 2: Configure Email (Optional but Recommended)

The system uses PHP's `mail()` function by default. For production environments, you should configure your server's mail settings or integrate a more robust email service.

#### Option A: Server Mail Configuration
Ensure your server has `sendmail` or a similar mail transfer agent configured.

#### Option B: Use PHPMailer (Recommended for Production)
1. Install PHPMailer via Composer:
   ```bash
   composer require phpmailer/phpmailer
   ```

2. Update the `send_reset_email()` function in `includes/auth.php` to use PHPMailer:
   ```php
   use PHPMailer\PHPMailer\PHPMailer;
   use PHPMailer\PHPMailer\Exception;

   function send_reset_email(string $email, string $token): bool {
       $mail = new PHPMailer(true);
       try {
           // SMTP configuration
           $mail->isSMTP();
           $mail->Host = 'smtp.example.com';
           $mail->SMTPAuth = true;
           $mail->Username = 'your-email@example.com';
           $mail->Password = 'your-password';
           $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
           $mail->Port = 587;

           // Email content
           $resetUrl = app_base_url() . '/public/reset_password.php?token=' . urlencode($token);
           $mail->setFrom('noreply@example.com', 'UX Research Platform');
           $mail->addAddress($email);
           $mail->Subject = 'Password Reset Request';
           $mail->Body = "Click here to reset your password: {$resetUrl}";
           
           $mail->send();
           return true;
       } catch (Exception $e) {
           return false;
       }
   }
   ```

### Step 3: Test the System

1. **Navigate to login page**: https://truaxcreative.com/user_test/public/login.php
2. **Click "Forgot your password?"**
3. **Enter an admin or researcher email address**
4. **Check your email for the reset link** (or check the page for the link if email is not configured)
5. **Click the reset link and set a new password**
6. **Log in with your new password**

## User Flow

```
Login Page
    ↓
Click "Forgot your password?"
    ↓
Enter Email Address
    ↓
Receive Email with Reset Link
    ↓
Click Reset Link
    ↓
Enter New Password (+ Confirm)
    ↓
Password Reset Successfully
    ↓
Return to Login
```

## Security Features

1. **Token-based authentication**: Random 64-character tokens
2. **Time-limited tokens**: Expire after 1 hour
3. **One-time use**: Tokens are marked as used after password reset
4. **CSRF protection**: All forms include CSRF tokens
5. **Role restriction**: Only admin and researcher accounts can reset passwords
6. **No user enumeration**: Success message shown regardless of email existence
7. **Password hashing**: Uses PHP's `password_hash()` with bcrypt
8. **Automatic cleanup**: Expired tokens are removed automatically

## API Functions

All password reset functions are in `includes/auth.php`:

### `create_password_reset_token(string $email): ?string`
Creates a password reset token for a user.
- Returns token on success
- Returns null if user not found or not admin/researcher

### `validate_reset_token(string $token): ?int`
Validates a reset token.
- Returns user_id if valid
- Returns null if invalid/expired/used

### `reset_password_with_token(string $token, string $newPassword): bool`
Resets user password using a valid token.
- Returns true on success
- Returns false on failure

### `send_reset_email(string $email, string $token): bool`
Sends password reset email to user with absolute URL.
- Returns true if email sent
- Returns false on failure
- Uses `absolute_url()` to generate full domain URLs

### `cleanup_expired_reset_tokens(): void`
Removes expired and used tokens from database.

### Helper Functions (in `includes/helpers.php`)

#### `site_origin(): string`
Returns the site's origin (scheme + host).
- Example: `https://truaxcreative.com`

#### `absolute_url(string $path): string`
Converts a relative path to an absolute URL with full domain.
- Example: `absolute_url('/public/reset_password.php')` returns `https://truaxcreative.com/user_test/public/reset_password.php`

## Troubleshooting

### Email Not Sending
If emails are not being sent:
1. Check server mail configuration
2. View the reset link directly on the "Forgot Password" page (shown when email fails)
3. Consider implementing PHPMailer for more reliable email delivery
4. Check server logs for email errors

### Token Invalid/Expired
- Tokens expire after 1 hour
- Tokens can only be used once
- Request a new reset link if expired

### Password Reset Not Working
1. Verify the database table was created successfully
2. Check that the user has role 'admin' or 'researcher'
3. Ensure CSRF tokens are enabled in session
4. Check server error logs for PHP errors

## Maintenance

### Cleanup Old Tokens
The system automatically cleans up expired tokens when the reset password page is accessed. You can also run cleanup manually:

```php
<?php
require_once __DIR__ . '/includes/auth.php';
cleanup_expired_reset_tokens();
echo "Cleanup complete.";
?>
```

Or via SQL:
```sql
DELETE FROM password_resets WHERE expires_at < NOW() OR used = 1;
```

### Monitoring
Monitor the `password_resets` table for:
- High number of reset requests (potential abuse)
- Failed reset attempts
- Token usage patterns

## Production Recommendations

1. **Use HTTPS**: Ensure all password reset pages use HTTPS
2. **Rate limiting**: Implement rate limiting on reset requests
3. **Email service**: Use a dedicated email service (SendGrid, Mailgun, AWS SES)
4. **Logging**: Log all password reset attempts for security auditing
5. **Two-factor authentication**: Consider adding 2FA for additional security
6. **Password complexity**: Add more password requirements if needed

## Support

For issues or questions:
- Check the troubleshooting section above
- Review server error logs
- Verify database table structure
- Ensure all files are properly uploaded

---

**Last Updated**: October 8, 2025
**Version**: 1.0

