User Registration Guide ​
Learn how to implement user registration in your application using Flowless.
Overview ​
User registration is the process of creating a new user account. Flowless provides a simple API endpoint that handles:
- Email/username validation
- Password hashing (Argon2id)
- Session creation
- Email verification (optional)
- User profile creation
Basic Registration Flow ​
Implementation ​
Frontend (React) ​
typescript
import { useState } from 'react';
interface RegisterFormData {
email: string;
password: string;
name: string;
last_name: string;
}
function RegisterForm() {
const [formData, setFormData] = useState<RegisterFormData>({
email: '',
password: '',
name: '',
last_name: '',
});
const [errors, setErrors] = useState<string[]>([]);
const [loading, setLoading] = useState(false);
const validateForm = (): boolean => {
const newErrors: string[] = [];
// Email validation
if (!formData.email) {
newErrors.push('Email is required');
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
newErrors.push('Invalid email format');
}
// Password validation
if (!formData.password) {
newErrors.push('Password is required');
} else if (formData.password.length < 8) {
newErrors.push('Password must be at least 8 characters');
} else if (!/[A-Z]/.test(formData.password)) {
newErrors.push('Password must contain uppercase letter');
} else if (!/[a-z]/.test(formData.password)) {
newErrors.push('Password must contain lowercase letter');
} else if (!/[0-9]/.test(formData.password)) {
newErrors.push('Password must contain number');
} else if (!/[!@#$%^&*]/.test(formData.password)) {
newErrors.push('Password must contain special character');
}
// Name validation
if (!formData.name) {
newErrors.push('First name is required');
}
setErrors(newErrors);
return newErrors.length === 0;
};
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!validateForm()) {
return;
}
setLoading(true);
setErrors([]);
try {
const response = await fetch(
`${import.meta.env.VITE_FLOWLESS_URL}/auth/register`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
email: formData.email.toLowerCase(),
password: formData.password,
name: formData.name,
last_name: formData.last_name,
}),
}
);
const data = await response.json();
if (!data.success) {
setErrors([data.error]);
return;
}
// Store session ID
localStorage.setItem('session_id', data.data.session.session_id);
localStorage.setItem('user_data', JSON.stringify(data.data.user));
// Redirect to dashboard or show verification message
if (data.data.user.is_verified) {
window.location.href = '/dashboard';
} else {
window.location.href = '/verify-email';
}
} catch (error) {
setErrors(['Registration failed. Please try again.']);
} finally {
setLoading(false);
}
};
return (
<form onSubmit={handleSubmit}>
<h2>Create Account</h2>
{errors.length > 0 && (
<div className="errors">
{errors.map((error, index) => (
<p key={index}>{error}</p>
))}
</div>
)}
<input
type="email"
placeholder="Email"
value={formData.email}
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
required
/>
<input
type="password"
placeholder="Password"
value={formData.password}
onChange={(e) => setFormData({ ...formData, password: e.target.value })}
required
/>
<input
type="text"
placeholder="First Name"
value={formData.name}
onChange={(e) => setFormData({ ...formData, name: e.target.value })}
required
/>
<input
type="text"
placeholder="Last Name"
value={formData.last_name}
onChange={(e) => setFormData({ ...formData, last_name: e.target.value })}
/>
<button type="submit" disabled={loading}>
{loading ? 'Creating Account...' : 'Sign Up'}
</button>
</form>
);
}
export default RegisterForm;API Reference ​
Endpoint ​
http
POST /auth/registerRequest Body ​
json
{
"email": "user@example.com",
"password": "SecurePassword123!",
"name": "John",
"last_name": "Doe",
"username": "johndoe",
"phone": "+1234567890"
}Response ​
json
{
"success": true,
"data": {
"user": {
"id": "usr_1234567890",
"email": "user@example.com",
"name": "John",
"last_name": "Doe",
"is_verified": false,
"created_at": "2025-12-07T10:00:00Z"
},
"session": {
"session_id": "ses_abcdefghijk",
"expires_at": "2025-12-14T10:00:00Z"
}
}
}Best Practices ​
1. Validate on Frontend ​
Always validate user input before sending to the API:
typescript
function validateEmail(email: string): boolean {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
function validatePassword(password: string): boolean {
return (
password.length >= 8 &&
/[A-Z]/.test(password) &&
/[a-z]/.test(password) &&
/[0-9]/.test(password) &&
/[!@#$%^&*]/.test(password)
);
}2. Normalize Email ​
Always convert email to lowercase:
typescript
const email = userInput.toLowerCase().trim();3. Show Password Strength ​
typescript
function getPasswordStrength(password: string): string {
let strength = 0;
if (password.length >= 8) strength++;
if (password.length >= 12) strength++;
if (/[A-Z]/.test(password)) strength++;
if (/[a-z]/.test(password)) strength++;
if (/[0-9]/.test(password)) strength++;
if (/[!@#$%^&*]/.test(password)) strength++;
if (strength <= 2) return 'Weak';
if (strength <= 4) return 'Medium';
return 'Strong';
}4. Handle Errors Gracefully ​
typescript
try {
const response = await register(formData);
} catch (error) {
if (error.message === 'Email already registered') {
setErrors(['This email is already in use. Try logging in instead.']);
} else {
setErrors(['Registration failed. Please try again.']);
}
}Next Steps ​
- Login Flow - Implement login
- Email Verification - Verify user emails
- Password Reset - Reset passwords
- Social Login - Add OAuth