Initial commit: Open sourcing all of the Maple Open Technologies code.

This commit is contained in:
Bartlomiej Mika 2025-12-02 14:33:08 -05:00
commit 755d54a99d
2010 changed files with 448675 additions and 0 deletions

View file

@ -0,0 +1,487 @@
# 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)