Spaces:
Sleeping
Sleeping
| # Admin Registration OTP Email Template | |
| ## Overview | |
| When someone attempts to register as a Platform Admin, the configured admin email receives a detailed notification with the registration request details and an OTP code. | |
| ## Email Template | |
| **Template File:** `src/app/templates/emails/admin_registration_otp.html` | |
| ## Information Displayed | |
| The admin receives an email containing: | |
| ### 1. Registration Details | |
| - **Name:** Full name of the person registering | |
| - **Email:** Email address being registered | |
| - **Phone:** Phone number provided | |
| - **IP Address:** Source IP of the registration request | |
| - **Timestamp:** UTC timestamp when registration was initiated | |
| - **Location:** (Optional, if available from IP geolocation) | |
| ### 2. OTP Code | |
| - Large, easy-to-read verification code | |
| - Expiry time (default: 10 minutes) | |
| ### 3. Security Warnings | |
| - Action required instructions | |
| - Platform Admin access level warning | |
| - Instructions for handling suspicious requests | |
| ## Sample Email Content | |
| ``` | |
| π¨ Platform Admin Registration Request | |
| Someone is attempting to register a Platform Admin account with the following details: | |
| βββββββββββββββββββββββββββββββββββββββββββ | |
| β π Registration Details β | |
| βββββββββββββββββββββββββββββββββββββββββββ€ | |
| β Name: John Doe β | |
| β Email: john@example.com β | |
| β Phone: +1234567890 β | |
| β IP Address: 192.168.1.100 β | |
| β Timestamp: 2024-01-15 14:30:00 UTC β | |
| βββββββββββββββββββββββββββββββββββββββββββ | |
| π Action Required: | |
| If you recognize this person and approve their registration, share the OTP code below with them. | |
| Otherwise, ignore this email. | |
| Verification code for Platform Admin Registration: | |
| βββββββββββββββββ | |
| β 6 1 3 2 8 1 β | |
| βββββββββββββββββ | |
| This code will expire in 10 minutes. | |
| β οΈ Security Warning: | |
| Only share this code if you personally verified and approved this registration request. | |
| Platform Admin accounts have full system access. | |
| If you don't recognize this registration attempt: | |
| β’ Do not share the OTP code | |
| β’ Let it expire (10 minutes) | |
| β’ Contact your security team if you're concerned | |
| ``` | |
| ## Implementation Details | |
| ### Trigger Point | |
| **Endpoint:** `POST /auth/send-admin-otp` | |
| **Request Body:** | |
| ```json | |
| { | |
| "email": "admin@example.com", | |
| "first_name": "John", | |
| "last_name": "Doe", | |
| "phone": "+1234567890" | |
| } | |
| ``` | |
| ### Template Selection Logic | |
| **File:** `src/app/services/otp_service.py` (line ~430-450) | |
| ```python | |
| # Determine template based on registration type | |
| is_admin_registration = additional_metadata and 'admin_registration' in additional_metadata | |
| template_name = 'admin_registration_otp' if is_admin_registration else 'otp' | |
| subject = 'SwiftOps Platform Admin Registration Request' if is_admin_registration else 'Your SwiftOps Verification Code' | |
| ``` | |
| ### Template Variables | |
| The following Jinja2 variables are passed to the template: | |
| **From OTP Service:** | |
| - `code` - The 6-digit OTP code | |
| - `purpose` - "Platform Admin Registration" | |
| - `validity_minutes` - Expiry time (default: 10) | |
| **From Auth Endpoint (additional_metadata):** | |
| - `admin_registration` - Boolean flag (true) | |
| - `registrant_name` - Full name (first + last) | |
| - `registrant_email` - Email being registered | |
| - `registrant_phone` - Phone number or "Not provided" | |
| - `ip_address` - Source IP address | |
| - `timestamp` - UTC timestamp | |
| **Auto-added by NotificationService:** | |
| - `app_domain` - Application domain (e.g., "swiftops.atomio.tech") | |
| - `current_year` - Current year for copyright footer | |
| ### IP Address Capture | |
| **File:** `src/app/api/v1/auth.py` (line ~85-88) | |
| ```python | |
| # Capture request metadata for security audit | |
| from datetime import datetime | |
| ip_address = request.client.host if request.client else "Unknown" | |
| timestamp = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC") | |
| ``` | |
| The IP address is captured from the FastAPI `Request` object at the time of registration. | |
| ## Security Benefits | |
| 1. **Identity Verification:** Admin sees WHO is attempting to register before approving | |
| 2. **Audit Trail:** IP address and timestamp provide forensic data | |
| 3. **Social Engineering Protection:** Admin can verify offline before sharing OTP | |
| 4. **Suspicious Activity Detection:** Unusual names, IPs, or timing patterns are visible | |
| 5. **Access Control:** Emphasizes that Platform Admin has full system access | |
| ## Configuration | |
| ### Required Environment Variables | |
| **Admin Email Recipient:** | |
| ```env | |
| PLATFORM_ADMIN_EMAIL=admin@yourcompany.com | |
| ``` | |
| This email receives all Platform Admin registration OTP requests. | |
| ### Optional Configuration | |
| **IP Geolocation (Future Enhancement):** | |
| If you want to add location data based on IP address, integrate a service like: | |
| - MaxMind GeoIP2 | |
| - ipapi.co | |
| - ip-api.com | |
| Add location lookup in `auth.py` before sending OTP: | |
| ```python | |
| # Future enhancement - IP geolocation | |
| try: | |
| location = await get_location_from_ip(ip_address) | |
| except Exception: | |
| location = None | |
| ``` | |
| ## Testing | |
| ### Test the Registration Flow | |
| 1. **Send OTP Request:** | |
| ```bash | |
| curl -X POST http://localhost:8000/api/v1/auth/send-admin-otp \ | |
| -H "Content-Type: application/json" \ | |
| -d '{ | |
| "email": "test@example.com", | |
| "first_name": "Test", | |
| "last_name": "User", | |
| "phone": "+1234567890" | |
| }' | |
| ``` | |
| 2. **Check Admin Email:** | |
| - Email sent to `PLATFORM_ADMIN_EMAIL` | |
| - Should display all registration details | |
| - Should show OTP code prominently | |
| - Should include security warnings | |
| 3. **Complete Registration:** | |
| ```bash | |
| curl -X POST http://localhost:8000/api/v1/auth/register \ | |
| -H "Content-Type: application/json" \ | |
| -d '{ | |
| "email": "test@example.com", | |
| "first_name": "Test", | |
| "last_name": "User", | |
| "phone": "+1234567890", | |
| "password": "SecurePassword123!", | |
| "otp_code": "123456" | |
| }' | |
| ``` | |
| ## Email Template Customization | |
| ### Styling Changes | |
| The template uses inline CSS for maximum email client compatibility. Key style sections: | |
| **Color Scheme:** | |
| - Red theme (#dc2626) for Platform Admin emphasis | |
| - Yellow warnings (#f59e0b) for action required | |
| - Gray text (#6b7280) for labels | |
| **Layout:** | |
| - 600px width for optimal viewing | |
| - Responsive table layout | |
| - Mobile-friendly sizing | |
| ### Content Modifications | |
| **To customize warnings or messaging:** | |
| Edit `src/app/templates/emails/admin_registration_otp.html`: | |
| ```html | |
| <!-- Main warning box --> | |
| <div style="background-color: #fef3c7; ..."> | |
| <p>Your custom message here</p> | |
| </div> | |
| <!-- Security warning --> | |
| <div style="background-color: #fee2e2; ..."> | |
| <p>Your custom security message</p> | |
| </div> | |
| ``` | |
| **To add additional fields:** | |
| 1. Add variable to `additional_metadata` in `auth.py` | |
| 2. Add table row in template: | |
| ```html | |
| <tr> | |
| <td style="color: #6b7280; font-size: 14px; vertical-align: top;"> | |
| <strong>Your Field:</strong> | |
| </td> | |
| <td style="color: #111827; font-size: 14px;"> | |
| {{ your_variable }} | |
| </td> | |
| </tr> | |
| ``` | |
| ## Comparison with Generic OTP Template | |
| ### Generic OTP (`otp.html`) | |
| - Used for: Password resets, 2FA, general verifications | |
| - Recipient: The user requesting the action | |
| - Context: Minimal - just code and purpose | |
| - Security: Assumes user initiated the request | |
| ### Admin Registration OTP (`admin_registration_otp.html`) | |
| - Used for: Platform Admin account creation | |
| - Recipient: Configured admin email (not the registrant) | |
| - Context: Full details about WHO is registering | |
| - Security: Admin must verify offline before sharing OTP | |
| ## Related Documentation | |
| - **Registration Flow:** `docs/agent/SETUP_COMPLETE.md` | |
| - **Auth API:** `docs/dev/AUTH_API_GUIDE.md` | |
| - **OTP Integration:** `docs/OTP_INTEGRATION_GUIDE.md` | |
| - **User Management:** `docs/USER_MANAGEMENT_IMPLEMENTATION.md` | |
| ## Troubleshooting | |
| ### Email Not Received | |
| 1. **Check PLATFORM_ADMIN_EMAIL:** | |
| ```bash | |
| echo $PLATFORM_ADMIN_EMAIL | |
| ``` | |
| 2. **Check Resend API Configuration:** | |
| ```bash | |
| echo $RESEND_API_KEY | |
| echo $RESEND_FROM_EMAIL | |
| ``` | |
| 3. **Check Logs:** | |
| ```bash | |
| # Look for OTP send confirmation | |
| grep "Platform admin registration OTP sent" logs/app.log | |
| ``` | |
| ### Template Not Found Error | |
| Ensure template file exists: | |
| ```bash | |
| ls src/app/templates/emails/admin_registration_otp.html | |
| ``` | |
| If missing, the system will fall back to generic `otp.html` template. | |
| ### IP Address Shows as "Unknown" | |
| This can happen when: | |
| - Running behind a proxy without X-Forwarded-For headers | |
| - Testing locally (may show 127.0.0.1) | |
| - Request object doesn't have client property | |
| Check FastAPI proxy configuration if behind nginx/load balancer. | |
| ## Future Enhancements | |
| ### Planned Features | |
| 1. **IP Geolocation:** Show city/country from IP address | |
| 2. **User Agent Tracking:** Display browser/device information | |
| 3. **Risk Scoring:** Highlight suspicious registration patterns | |
| 4. **Multi-Admin Approval:** Require multiple admin OTP codes | |
| 5. **Time-based Restrictions:** Only allow registrations during business hours | |
| 6. **Email Verification:** Require email verification before sending OTP | |
| ### Extensibility Points | |
| The template system is designed for easy extension: | |
| 1. **Custom Templates per Role:** | |
| ```python | |
| if role == 'client_admin': | |
| template_name = 'client_admin_registration_otp' | |
| elif role == 'contractor_admin': | |
| template_name = 'contractor_admin_registration_otp' | |
| ``` | |
| 2. **Webhook Notifications:** | |
| Send registration events to Slack/Teams/Discord | |
| 3. **Approval Workflow:** | |
| Store pending registrations in database for manual approval | |
| ## Summary | |
| The admin registration OTP email provides comprehensive security context for high-privilege account creation. By showing WHO is registering, FROM WHERE, and WHEN, it enables admins to make informed decisions about sharing verification codes. | |
| This approach balances user experience (simple registration form) with security (admin verification before account creation). | |