14 KiB
Registration API Implementation
This document describes the complete implementation of the user registration feature for the MaplePress frontend, integrated with the MaplePress backend API.
Overview
The registration feature allows new users to create an account and automatically sets up their tenant (organization) in a single step. Upon successful registration, users receive authentication tokens and are automatically logged in.
Backend API Endpoint
Endpoint: POST /api/v1/register
Authentication: None required (public endpoint)
Documentation: /cloud/maplepress-backend/docs/API.md (lines 66-166)
Request Structure
{
"email": "user@example.com",
"password": "SecurePassword123!",
"confirm_password": "SecurePassword123!",
"first_name": "John",
"last_name": "Doe",
"tenant_name": "Acme Corporation",
"timezone": "America/New_York",
"agree_terms_of_service": true,
"agree_promotions": false,
"agree_to_tracking_across_third_party_apps_and_services": false
}
Response Structure
{
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"user_email": "user@example.com",
"user_name": "John Doe",
"user_role": "manager",
"tenant_id": "650e8400-e29b-41d4-a716-446655440000",
"tenant_name": "Acme Corporation",
"tenant_slug": "acme-corp",
"session_id": "750e8400-e29b-41d4-a716-446655440000",
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"access_expiry": "2024-10-24T12:00:00Z",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_expiry": "2024-11-24T00:00:00Z",
"created_at": "2024-10-24T00:00:00Z"
}
Frontend Implementation
1. RegisterService (src/services/API/RegisterService.js)
Handles direct communication with the backend registration API.
Key Features:
- Request validation (required fields, terms agreement)
- Request body formatting (snake_case for backend)
- Response transformation (camelCase for frontend)
- User-friendly error message mapping
- Tenant slug validation and generation utilities
Methods:
register(data)- Main registration methodvalidateTenantSlug(slug)- Validate slug formatgenerateTenantSlug(name)- Auto-generate slug from name
Usage:
import RegisterService from './services/API/RegisterService';
const response = await RegisterService.register({
email: "user@example.com",
password: "SecurePassword123!",
confirmPassword: "SecurePassword123!",
first_name: "John",
last_name: "Doe",
tenant_name: "Acme Corp",
agree_terms_of_service: true,
});
2. AuthManager (src/services/Manager/AuthManager.js)
Manages authentication state, token storage, and session lifecycle.
Key Features:
- Token management (access & refresh tokens)
- LocalStorage persistence
- Token expiry checking
- User and tenant data storage
- Session initialization and cleanup
New Methods:
register(registrationData)- Register and store auth datastoreAuthData(authResponse)- Store tokens and user dataclearSession()- Clear all auth dataisTokenExpired(expiry)- Check token expirygetTenant()- Get current tenant information
Storage Keys:
maplepress_access_token
maplepress_refresh_token
maplepress_access_expiry
maplepress_refresh_expiry
maplepress_user
maplepress_tenant
maplepress_session_id
3. Register Page (src/pages/Auth/Register.jsx)
Complete registration form with all required fields.
Form Sections:
-
Personal Information
- First Name (required)
- Last Name (required)
- Email Address (required)
- Password (required, min 8 chars)
- Confirm Password (required)
-
Organization Information
- Organization Name (required, slug auto-generated by backend)
-
Terms and Consent
- Terms of Service agreement (required)
- Promotional emails (optional)
Features:
- Password match validation (backend-validated)
- Terms of service requirement
- Automatic timezone detection
- Loading state during submission
- RFC 9457 error message display with field-specific errors
Data Flow
User fills form
↓
Register.jsx validates data
↓
AuthManager.register(data)
↓
RegisterService.register(data)
↓
HTTP POST to /api/v1/register
↓
Backend validates and creates user + tenant
↓
Backend returns tokens and user data
↓
RegisterService transforms response
↓
AuthManager stores tokens in localStorage
↓
User redirected to /dashboard
Validation Rules
Frontend Validation
- Email: Required, valid email format
- Password:
- Required
- Minimum 8 characters
- Confirm Password:
- Required
- Must match password (validated by backend)
- Name: Required
- Tenant Name: Required
- Tenant Slug:
- Required
- Only lowercase letters, numbers, and hyphens
- Validated by regex:
/^[a-z0-9-]+$/
- Terms of Service: Must be checked
Backend Validation
Backend performs additional validation:
- Email normalization and format validation
- Password strength requirements (uppercase, lowercase, number, special char)
- Password confirmation matching
- Tenant slug uniqueness
- Email uniqueness
- No HTML in text fields
- Input sanitization
Error Handling
RFC 9457 (Problem Details for HTTP APIs)
The backend returns validation errors in RFC 9457 format, which provides a structured, machine-readable error response.
Error Response Structure:
{
"type": "about:blank",
"title": "Validation Error",
"status": 400,
"detail": "One or more validation errors occurred",
"errors": {
"email": ["Invalid email format"],
"password": ["Field is required", "Password must be at least 8 characters"],
"confirm_password": ["Field is required", "Passwords do not match"],
"first_name": ["Field is required"],
"last_name": ["Field is required"],
"tenant_name": ["Field is required"],
"agree_terms_of_service": ["Must agree to terms of service"]
}
}
Content-Type: application/problem+json
Key Fields:
type: URI reference identifying the problem type (usesabout:blankfor generic errors)title: Short, human-readable summary of the error typestatus: HTTP status codedetail: Human-readable explanation of the errorerrors: Dictionary/map of field-specific validation errors (extension field)
Common Validation Errors
| Field | Error Message |
|---|---|
email: invalid email format |
|
email: email is required |
|
| password | password: password is required |
| password | password: password must be at least 8 characters |
| password | password: password must contain at least one uppercase letter (A-Z) |
| password | password: password must contain at least one lowercase letter (a-z) |
| password | password: password must contain at least one number (0-9) |
| password | password: password must contain at least one special character |
| confirm_password | confirm_password: field is required |
| confirm_password | confirm_password: passwords do not match |
| first_name | first_name: field is required |
| first_name | first_name: first_name must be between 1 and 100 characters |
| last_name | last_name: field is required |
| last_name | last_name: last_name must be between 1 and 100 characters |
| tenant_name | tenant_name: tenant_name is required |
| tenant_name | tenant_name: tenant_name must be between 1 and 100 characters |
| agree_terms_of_service | agree_terms_of_service: must agree to terms of service |
Frontend Error Parsing
The Register page component (src/pages/Auth/Register.jsx) includes a parseBackendError() function that:
- Checks if the error object contains RFC 9457
validationErrorsstructure - Iterates through the errors dictionary and maps each field to its error messages
- Joins multiple error messages for the same field with semicolons
- Displays field-specific errors with red borders and inline messages
- Shows an error summary box at the top with all errors listed
Error Parsing Implementation:
const parseBackendError = (error) => {
const fieldErrors = {};
let generalError = null;
// Check if error has RFC 9457 validation errors structure
if (error.validationErrors && typeof error.validationErrors === 'object') {
// Process each field's errors
Object.entries(error.validationErrors).forEach(([fieldName, errorMessages]) => {
if (Array.isArray(errorMessages) && errorMessages.length > 0) {
// Join multiple error messages for the same field
fieldErrors[fieldName] = errorMessages.join('; ');
}
});
// Use the detail as general error if available
if (error.message) {
generalError = error.message;
}
} else {
// Fallback for non-RFC 9457 errors
generalError = error.message || "An error occurred. Please try again.";
}
return { fieldErrors, generalError };
};
Example Error Display:
When submitting an empty form, the user sees:
- Error Summary Box: Lists all validation errors at the top of the form with the general message "One or more validation errors occurred"
- Highlighted Fields: Red border on email, password, first_name, last_name, tenant_name, etc.
- Inline Messages: Error text displayed below each affected field (e.g., "Field is required")
ApiClient Error Handling
The ApiClient (src/services/API/ApiClient.js) automatically parses RFC 9457 error responses and attaches the validation errors to the error object:
// Create error with RFC 9457 data if available
const error = new Error(
errorData.detail || errorData.message || `HTTP ${response.status}: ${response.statusText}`
);
// Attach RFC 9457 fields to error for parsing
if (errorData.errors) {
error.validationErrors = errorData.errors; // RFC 9457 validation errors
}
if (errorData.title) {
error.title = errorData.title;
}
if (errorData.status) {
error.status = errorData.status;
}
throw error;
Note: The frontend does not perform field validation - all validation, including password matching, is handled by the backend. The form submits whatever the user enters, and the backend returns comprehensive validation errors in RFC 9457 format.
Security Features
- Token Storage: Tokens stored in localStorage (client-side only)
- Token Expiry: Automatic expiry checking on initialization
- Password Validation: Client and server-side validation
- HTTPS Required: Production should use HTTPS
- Terms Agreement: Required before account creation
- Input Sanitization: Backend sanitizes all inputs
Testing the Registration Flow
1. Start Backend
cd cloud/mapleopentech-backend
task dev
2. Start Frontend
cd web/maplepress-frontend
npm run dev
3. Navigate to Registration
Open browser to: http://localhost:5173/register
4. Fill Form
- First Name: John (required)
- Last Name: Doe (required)
- Email: test@example.com
- Password: SecurePass123!
- Confirm Password: SecurePass123!
- Organization Name: Test Corp (slug auto-generated by backend)
- Terms of Service: ✓ (checked)
5. Submit
Click "Create Account" button
6. Expected Result
- Loading state appears
- Request sent to backend
- Tokens stored in localStorage
- User redirected to
/dashboard - Dashboard shows user information
7. Verify in Browser Console
// Check stored tokens
localStorage.getItem('maplepress_access_token')
localStorage.getItem('maplepress_user')
localStorage.getItem('maplepress_tenant')
// Check service instance
window.maplePressServices.authManager.isAuthenticated()
window.maplePressServices.authManager.getUser()
window.maplePressServices.authManager.getTenant()
Configuration
Environment Variables
Create .env file:
# Backend API URL
VITE_API_BASE_URL=http://localhost:8000
Production Configuration
For production:
VITE_API_BASE_URL=https://api.maplepress.io
Future Enhancements
Planned Features
- Email verification flow
- Password strength indicator
- Captcha integration
- Social authentication (Google, GitHub)
- Organization logo upload
- Custom domain support
- Invitation codes/referrals
- Account recovery flow
Security Improvements
- CSRF token implementation
- Rate limiting on frontend
- Session fingerprinting
- Two-factor authentication
- Password breach checking
- Secure token storage (HTTP-only cookies)
File Reference
Created Files
src/services/API/RegisterService.js
Modified Files
src/services/Manager/AuthManager.js
src/pages/Auth/Register.jsx
Backend Reference Files
cloud/maplepress-backend/docs/API.md
cloud/maplepress-backend/internal/interface/http/dto/gateway/register_dto.go
cloud/maplepress-backend/internal/interface/http/handler/gateway/register_handler.go
API Client Configuration
The ApiClient automatically handles:
- JSON content-type headers
- Request/response transformation
- Error parsing
- Authentication headers (for protected endpoints)
Base Configuration
API_CONFIG = {
baseURL: import.meta.env.VITE_API_BASE_URL || "http://localhost:8000",
timeout: 30000,
}
Support
For issues or questions:
- Check backend logs:
docker logs mapleopentech_backend - Check frontend console for errors
- Verify backend is running on port 8000
- Verify frontend environment variables
- Test backend endpoint directly with curl (see API.md)
Related Documentation
- ARCHITECTURE.md - Frontend architecture overview
- README.md - Getting started guide
- Backend API Documentation - Complete API reference