# Login API Implementation This document describes the complete implementation of the user login feature for the MaplePress frontend, integrated with the MaplePress backend API. ## Overview The login feature allows existing users to authenticate with their email and password credentials. Upon successful login, users receive authentication tokens and are automatically logged in to their dashboard. ## Backend API Endpoint **Endpoint**: `POST /api/v1/login` **Authentication**: None required (public endpoint) **Documentation**: `/cloud/maplepress-backend/docs/API.md` (lines 168-228) ### Request Structure ```json { "email": "user@example.com", "password": "SecurePassword123!" } ``` ### Response Structure ```json { "user_id": "550e8400-e29b-41d4-a716-446655440000", "user_email": "user@example.com", "user_name": "John Doe", "user_role": "user", "tenant_id": "650e8400-e29b-41d4-a716-446655440000", "session_id": "750e8400-e29b-41d4-a716-446655440000", "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "access_expiry": "2024-10-24T12:15:00Z", "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "refresh_expiry": "2024-10-31T00:00:00Z", "login_at": "2024-10-24T00:00:00Z" } ``` ### Key Differences from Registration The login endpoint differs from registration in several ways: - **Simpler Request**: Only email and password required - **No Tenant Details in Response**: Tenant name/slug not included - **Login Timestamp**: Includes `login_at` instead of `created_at` - **Existing Session**: Authenticates existing user, doesn't create new account ## Frontend Implementation ### 1. LoginService (`src/services/API/LoginService.js`) Handles direct communication with the backend login API. **Key Features:** - Request validation (required fields) - Request body formatting (snake_case for backend) - Response transformation (camelCase for frontend) - User-friendly error message mapping - Rate limit error handling - Account lockout detection **Methods:** - `login(credentials)` - Main login method **Usage:** ```javascript import LoginService from './services/API/LoginService'; const response = await LoginService.login({ email: "user@example.com", password: "SecurePassword123!", }); ``` ### 2. AuthManager Enhancement (`src/services/Manager/AuthManager.js`) Updated to support login functionality while maintaining registration support. **New/Updated Methods:** - `login(email, password)` - Login and store auth data - `storeAuthData(authResponse)` - Updated to handle optional tenant fields **Key Features:** - Handles both registration and login responses - Gracefully handles missing tenant name/slug from login - Maintains same token storage mechanism - Consistent session management **Login Flow:** ```javascript const authManager = useAuth().authManager; // Login await authManager.login("user@example.com", "password123"); // Check authentication if (authManager.isAuthenticated()) { const user = authManager.getUser(); const tenant = authManager.getTenant(); } ``` ### 3. Login Page (`src/pages/Auth/Login.jsx`) Simple and clean login form ready for production use. **Form Fields:** - Email Address (required) - Password (required) **Features:** - Email validation (HTML5 + backend) - Loading state during submission - Error message display - Navigation to registration - Navigation back to home ## Data Flow ``` User enters credentials ↓ Login.jsx validates data ↓ AuthManager.login(email, password) ↓ LoginService.login(credentials) ↓ HTTP POST to /api/v1/login ↓ Backend validates credentials ↓ Backend returns tokens and user data ↓ LoginService transforms response ↓ AuthManager stores tokens in localStorage ↓ User redirected to /dashboard ``` ## Validation Rules ### Frontend Validation 1. **Email**: Required, valid email format (HTML5) 2. **Password**: Required (no client-side length check for login) ### Backend Validation Backend performs: - Email format validation - Email normalization (lowercase, trim) - Password verification against stored hash - Rate limiting checks - Account lockout checks ## Error Handling ### Error Messages Errors are mapped to user-friendly messages: | Backend Error | Frontend Message | |--------------|------------------| | "Invalid email or password" | "Invalid email or password. Please try again." | | "X attempts remaining" | Original message with attempt counter | | "locked" or "Too many" | "Account temporarily locked due to too many failed attempts. Please try again later." | | "invalid email" | "Invalid email address." | ### Rate Limiting & Account Lockout The backend implements sophisticated rate limiting: **Per-IP Rate Limiting:** - Limit: Multiple attempts per 15 minutes - Response: `429 Too Many Requests` - Header: `Retry-After: 900` (15 minutes) **Per-Account Rate Limiting:** - Limit: 5 failed attempts - Lockout: 30 minutes after 5 failures - Response: `429 Too Many Requests` - Header: `Retry-After: 1800` (30 minutes) - Warning: Shows remaining attempts when ≤ 3 **Behavior:** 1. First 2 failures: Generic error message 2. 3rd-5th failure: Shows remaining attempts 3. After 5th failure: Account locked for 30 minutes 4. Successful login: Resets all counters ### Security Event Logging Backend logs security events for: - Failed login attempts (with email hash) - Successful logins (with email hash) - IP rate limit exceeded - Account lockouts ## Security Features 1. **Token Storage**: Tokens stored in localStorage 2. **Token Expiry**: Automatic expiry checking 3. **Rate Limiting**: Backend enforces rate limits 4. **Account Lockout**: Protects against brute force 5. **Email Normalization**: Prevents bypass via casing 6. **Secure Logging**: PII never logged, only hashes 7. **Password Hash Verification**: Uses bcrypt on backend ## Token Lifetime - **Access Token**: 15 minutes - **Refresh Token**: 7 days - **Session**: 14 days (max inactivity) ## Testing the Login Flow ### 1. Prerequisites Ensure you have a registered user. If not, register first: ```bash # Navigate to registration http://localhost:5173/register # Or use curl to register via backend curl -X POST http://localhost:8000/api/v1/register \ -H "Content-Type: application/json" \ -d '{ "email": "test@example.com", "password": "SecurePass123!", "name": "Test User", "tenant_name": "Test Corp", "tenant_slug": "test-corp", "agree_terms_of_service": true }' ``` ### 2. Start Services ```bash # Backend cd cloud/maplepress-backend task dev # Frontend cd web/maplepress-frontend npm run dev ``` ### 3. Navigate to Login Open browser to: `http://localhost:5173/login` ### 4. Fill Form - **Email**: test@example.com - **Password**: SecurePass123! ### 5. Submit Click "Sign In" button ### 6. Expected Result - Loading state appears ("Signing in...") - Request sent to backend - Tokens stored in localStorage - User redirected to `/dashboard` - Dashboard shows user information ### 7. Verify in Browser Console ```javascript // Check stored tokens localStorage.getItem('maplepress_access_token') localStorage.getItem('maplepress_user') localStorage.getItem('maplepress_tenant') // Check service instance window.maplePressServices.authManager.isAuthenticated() // true window.maplePressServices.authManager.getUser() // Returns: { id: "...", email: "test@example.com", name: "Test User", role: "..." } window.maplePressServices.authManager.getTenant() // Returns: { id: "...", name: null, slug: null } // Note: name/slug are null because login endpoint doesn't provide them ``` ## Error Testing ### Test Invalid Credentials ```javascript // In login form, enter: Email: test@example.com Password: WrongPassword123 // Expected: "Invalid email or password. Please try again." ``` ### Test Rate Limiting ```javascript // Attempt login 3 times with wrong password // Expected on 3rd attempt: "Invalid email or password. 2 attempts remaining before account lockout." // Attempt 2 more times // Expected on 5th attempt: "Account temporarily locked due to too many failed attempts. Please try again later." ``` ### Test Missing Fields ```javascript // Leave email blank // Expected: Browser validation error (HTML5 required) // Leave password blank // Expected: Browser validation error (HTML5 required) ``` ## Differences from Registration | Feature | Registration | Login | |---------|-------------|-------| | Request Fields | 10+ fields | 2 fields only | | Response Fields | Includes tenant name/slug | No tenant name/slug | | Timestamp | `created_at` | `login_at` | | Creates User | Yes | No | | Creates Tenant | Yes | No | | Terms Agreement | Required | Not needed | | Organization Info | Required | Not needed | ## Token Storage Compatibility Both registration and login use the same storage mechanism: ```javascript // Storage Keys (7 total) maplepress_access_token // JWT access token maplepress_refresh_token // JWT refresh token maplepress_access_expiry // ISO date string maplepress_refresh_expiry // ISO date string maplepress_user // JSON: {id, email, name, role} maplepress_tenant // JSON: {id, name, slug} maplepress_session_id // Session UUID ``` **Note**: After login, `tenant.name` and `tenant.slug` will be `null`. This is expected behavior. If needed, fetch tenant details separately using the `/api/v1/tenants/{id}` endpoint. ## Session Persistence Authentication state persists across: - Page refreshes - Browser restarts (if localStorage not cleared) - Tab changes Session is cleared on: - User logout - Token expiry detection - Manual localStorage clear ## Integration with Dashboard The dashboard automatically checks authentication: ```javascript // Dashboard.jsx useEffect(() => { if (!authManager.isAuthenticated()) { navigate("/login"); return; } const userData = authManager.getUser(); setUser(userData); }, [authManager, navigate]); ``` ## API Client Configuration The `ApiClient` automatically handles: - JSON content-type headers - Request/response transformation - Error parsing - Authentication headers (for protected endpoints) **Note**: Login endpoint doesn't require authentication headers, but subsequent API calls will use the stored access token. ## Future Enhancements ### Planned Features - [ ] "Remember Me" checkbox (longer session) - [ ] "Forgot Password" link - [ ] Social authentication (Google, GitHub) - [ ] Two-factor authentication (2FA/TOTP) - [ ] Session management (view active sessions) - [ ] Device fingerprinting - [ ] Suspicious login detection ### Security Improvements - [ ] CSRF token implementation - [ ] HTTP-only cookie option - [ ] Session fingerprinting - [ ] Geolocation tracking - [ ] Email notification on new login - [ ] Passwordless login option ## Troubleshooting ### "Invalid email or password" but credentials are correct **Possible causes:** 1. Email case sensitivity - backend normalizes to lowercase 2. Extra whitespace in password field 3. User not yet registered 4. Account locked due to previous failed attempts **Solution:** - Wait 30 minutes if account is locked - Try registering if user doesn't exist - Check browser console for detailed errors ### Tokens not being stored **Possible causes:** 1. localStorage disabled in browser 2. Private/Incognito mode restrictions 3. Browser extension blocking storage **Solution:** - Enable localStorage in browser settings - Use regular browser window - Disable blocking extensions temporarily ### Redirected back to login after successful login **Possible causes:** 1. Token expiry detection triggered 2. Token format invalid 3. localStorage cleared between operations **Solution:** - Check browser console for errors - Verify localStorage contains tokens - Check token expiry dates ## Related Files ### Created Files ``` src/services/API/LoginService.js ``` ### Modified Files ``` src/services/Manager/AuthManager.js src/pages/Auth/Login.jsx ``` ### Backend Reference Files ``` cloud/maplepress-backend/docs/API.md cloud/maplepress-backend/internal/interface/http/dto/gateway/login_dto.go cloud/maplepress-backend/internal/interface/http/handler/gateway/login_handler.go ``` ## Related Documentation - [REGISTRATION_API.md](./REGISTRATION_API.md) - Registration implementation - [ARCHITECTURE.md](./ARCHITECTURE.md) - Frontend architecture overview - [README.md](./README.md) - Getting started guide - [Backend API Documentation](../../cloud/maplepress-backend/docs/API.md) - Complete API reference ## Support For issues: 1. Check backend logs: `docker logs mapleopentech_backend` 2. Check browser console for errors 3. Verify backend is running on port 8000 4. Test backend endpoint directly with curl 5. Check rate limiting status (wait 30 minutes if locked)