# Function 6: Forgot Password - Completed โ
## ๐ฆ Files Created/Updated
### Frontend
1. **`client/src/pages/auth/ForgotPasswordPage.tsx`** - Forgot password form component
2. **`client/src/pages/auth/index.ts`** - Export ForgotPasswordPage
3. **`client/src/App.tsx`** - Route `/forgot-password`
### Backend
4. **`server/src/controllers/authController.js`** - forgotPassword() & resetPassword()
5. **`server/src/routes/authRoutes.js`** - Routes for forgot/reset password
## โจ Main Features
### 1. Form State (Initial)
```
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ๐จ Hotel Icon (Blue) โ
โ Forgot password? โ
โ Enter email to receive link... โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ โ Email โ โ
โ โ [๐ง email@example.com ] โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ
โ โ [๐ค Send reset link] โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค โ
โ โ โ Back to login โ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ Don't have an account? Sign up now โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
```
### 2. Success State (After Submit)
```
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ
Success Icon โ
โ โ
โ Email has been sent! โ
โ We have sent a link to โ
โ user@example.com โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ โน๏ธ Note: โ
โ โข Link is valid for 1 hour โ
โ โข Check Spam/Junk folder โ
โ โข If not received, try again โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ [๐ง Resend email] โ
โ [โ Back to login] โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
```
### 3. Two-State Design Pattern
โ
**Form State** - Enter email
โ
**Success State** - Display confirmation & instructions
State management:
```typescript
const [isSuccess, setIsSuccess] = useState(false);
const [submittedEmail, setSubmittedEmail] = useState('');
```
## ๐ง Detailed Features
### 1. Validation (Yup Schema)
```typescript
email:
- Required: "Email is required"
- Valid format: "Invalid email format"
- Trim whitespace
```
### 2. Form Field
- **Email input** with Mail icon
- Auto-focus when page loads
- Validation real-time
- Error message inline
### 3. Submit Button States
```tsx
{isLoading ? (
<>
Processing...
>
) : (
<>
Send reset link
>
)}
```
### 4. Success Features
โ
**Visual Confirmation**
- Green checkmark icon
- Success message
- Display submitted email
โ
**User Instructions**
- Link expires in 1 hour
- Check spam folder
- Can resend email
โ
**Action Buttons**
- "Resend email" - Reset to form state
- "Back to login" - Navigate to /login
### 5. Help Section
```tsx
Need help?
Contact: support@hotel.com or 1900-xxxx
```
## ๐ Backend Integration
### API Endpoint: Forgot Password
```
POST /api/auth/forgot-password
```
**Request Body:**
```json
{
"email": "user@example.com"
}
```
**Response (Success):**
```json
{
"status": "success",
"message": "Password reset link has been sent to your email"
}
```
**Implementation:**
```javascript
const forgotPassword = async (req, res, next) => {
// 1. Find user by email
// 2. Generate crypto reset token (32 bytes)
// 3. Hash token with SHA256
// 4. Save to password_reset_tokens table
// 5. Expires in 1 hour
// 6. TODO: Send email with reset link
// 7. Return success (prevent email enumeration)
};
```
### API Endpoint: Reset Password
```
POST /api/auth/reset-password
```
**Request Body:**
```json
{
"token": "reset_token_from_email",
"password": "NewPassword123@"
}
```
**Response (Success):**
```json
{
"status": "success",
"message": "Password has been reset successfully"
}
```
**Implementation:**
```javascript
const resetPassword = async (req, res, next) => {
// 1. Hash incoming token
// 2. Find valid token in DB (not expired)
// 3. Find user by user_id
// 4. Hash new password with bcrypt
// 5. Update user password
// 6. Delete used token
// 7. TODO: Send confirmation email
// 8. Return success
};
```
## ๐ Security Features
### 1. Token Generation
```javascript
// Generate random 32-byte token
const resetToken = crypto.randomBytes(32).toString('hex');
// Hash with SHA256 before storing
const hashedToken = crypto
.createHash('sha256')
.update(resetToken)
.digest('hex');
```
### 2. Token Storage
- Stored in `password_reset_tokens` table
- Hashed (SHA256)
- Expires in 1 hour
- One token per user (old tokens deleted)
### 3. Email Enumeration Prevention
```javascript
// Always return success, even if email not found
if (!user) {
return res.status(200).json({
status: 'success',
message: 'If email exists, reset link has been sent'
});
}
```
### 4. Token Validation
```javascript
// Check token exists and not expired
const resetToken = await PasswordResetToken.findOne({
where: {
token: hashedToken,
expires_at: { [Op.gt]: new Date() }
}
});
```
## ๐ Database Schema
### password_reset_tokens Table
```sql
CREATE TABLE password_reset_tokens (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
token VARCHAR(255) NOT NULL,
expires_at DATETIME NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id)
);
```
## ๐จ Design & Styling
**Color Scheme:**
- Primary: blue-600, blue-700
- Background: gradient from-blue-50 to-indigo-100
- Success: green-100, green-600
- Info: blue-50, blue-200
- Text: gray-600, gray-700, gray-900
**Icons:**
- ๐จ Hotel - Main logo
- ๐ง Mail - Email input
- ๐ค Send - Submit button
- โณ Loader2 - Loading spinner
- โ
CheckCircle - Success state
- โ ArrowLeft - Back navigation
## ๐ User Flow
```
1. User visits /forgot-password
โ
2. Enter email address
โ
3. Click "Send reset link"
โ
4. Frontend validation (Yup)
โ
5. Call useAuthStore.forgotPassword()
โ
6. API POST /api/auth/forgot-password
โ
7. Backend:
- Generate token
- Save to DB
- TODO: Send email
โ
8. Frontend shows success state
โ
9. User receives email (TODO)
โ
10. Click link โ /reset-password/:token
โ
11. Enter new password (Function 7)
```
## ๐งช Test Scenarios
### Test Case 1: Valid email
```
Input: email = "user@example.com"
Expected:
- API called successfully
- Success state shown
- Email displayed correctly
- Instructions visible
```
### Test Case 2: Invalid email format
```
Input: email = "notanemail"
Expected:
- Validation error: "Invalid email format"
- Form not submitted
```
### Test Case 3: Empty email
```
Input: email = ""
Expected:
- Validation error: "Email is required"
- Form not submitted
```
### Test Case 4: Loading state
```
Action: Submit form
Expected:
- Button disabled
- Spinner shows
- Text: "Processing..."
```
### Test Case 5: Resend email
```
Action: Click "Resend email" in success state
Expected:
- Return to form state
- Email field cleared
- Error cleared
```
### Test Case 6: Back to login
```
Action: Click "Back to login"
Expected:
- Navigate to /login
```
### Test Case 7: Email not found (Backend)
```
Input: email = "nonexistent@example.com"
Expected:
- Still return success (security)
- No error shown to user
```
### Test Case 8: Token expiry (Backend)
```
Scenario: Token created 2 hours ago
Expected:
- Reset fails
- Error: "Invalid or expired reset token"
```
## ๐ Code Quality
โ
**TypeScript**: Full type safety
โ
**React Hook Form**: Optimized performance
โ
**Yup Validation**: Schema-based validation
โ
**State Management**: Local state for success toggle
โ
**Error Handling**: Try-catch blocks
โ
**Security**: Token hashing, email enumeration prevention
โ
**UX**: Clear instructions, help section
โ
**Accessibility**: Labels, autocomplete, focus management
โ
**Responsive**: Mobile-friendly
โ
**80 chars/line**: Code formatting
## ๐ Integration Points
### useAuthStore.forgotPassword()
```typescript
const { forgotPassword, isLoading, error, clearError } =
useAuthStore();
await forgotPassword({ email: data.email });
```
### Success Handling
```typescript
await forgotPassword({ email: data.email });
setIsSuccess(true); // Show success state
```
### Error Handling
```typescript
try {
await forgotPassword({ email });
} catch (error) {
// Error displayed via store.error
console.error('Forgot password error:', error);
}
```
## ๐ Usage
### Test Frontend
```bash
URL: http://localhost:5173/forgot-password
Test Data:
Email: admin@hotel.com (from seed data)
```
### Test Backend API
```bash
curl -X POST http://localhost:3000/api/auth/forgot-password \
-H "Content-Type: application/json" \
-d '{"email":"admin@hotel.com"}'
```
Expected response:
```json
{
"status": "success",
"message": "Password reset link has been sent to your email"
}
```
Ensure SMTP is configured in `server/.env` and that the server
is able to send emails. The application must never log raw reset
tokens or reset URLs in production.
## โ ๏ธ TODO: Email Service
The project must send real emails via SMTP in production and must
never expose raw reset tokens in logs. To enable email sending:
1. Install `nodemailer` in the `server` package and configure
SMTP credentials in `server/.env` (`MAIL_HOST`, `MAIL_PORT`,
`MAIL_USER`, `MAIL_PASS`, `MAIL_FROM`). Do not commit these
credentials to source control.
2. Implement a mail helper (e.g. `server/src/utils/mailer.js`) that
uses the SMTP settings. Ensure it throws or fails when SMTP
credentials are missing so that emails are not silently dropped.
3. Use the mail helper to send the reset email with a link built as
`${process.env.CLIENT_URL}/reset-password/${resetToken}`.
4. Important: never log the raw `resetToken` or the reset URL. If
email sending fails, log a generic error and surface a safe
message to the user.
## โ
Checklist
- [x] โ
Create ForgotPasswordPage.tsx
- [x] โ
Implement React Hook Form
- [x] โ
Add Yup validation
- [x] โ
Two-state design (form + success)
- [x] โ
Loading state
- [x] โ
Error display
- [x] โ
Success state with instructions
- [x] โ
Resend email button
- [x] โ
Back to login navigation
- [x] โ
Help section
- [x] โ
Integration with useAuthStore
- [x] โ
Add route to App.tsx
- [x] โ
Backend: forgotPassword() method
- [x] โ
Backend: resetPassword() method
- [x] โ
Backend: Routes added
- [x] โ
Token generation & hashing
- [x] โ
Token expiry (1 hour)
- [x] โ
Security: Email enumeration prevention
- [ ] โณ TODO: Send actual email (nodemailer)
- [ ] โณ TODO: Email templates
## ๐ Related Files
- `client/src/pages/auth/LoginPage.tsx` - Login form
- `client/src/pages/auth/RegisterPage.tsx` - Register form
- `client/src/utils/validationSchemas.ts` - Validation schemas
- `client/src/store/useAuthStore.ts` - Auth state
- `server/src/controllers/authController.js` - Auth logic
- `server/src/routes/authRoutes.js` - Auth routes
- `server/src/databases/models/PasswordResetToken.js` - Token model
---
**Status:** โ
Function 6 completed
**Next:** Function 7 - Reset Password (form to change password with token)
**Test URL:** http://localhost:5173/forgot-password
**API:** POST /api/auth/forgot-password