Overview
The Church Management System uses a two-tier user system: authentication credentials stored separately from profile information. This guide covers user registration, login, and profile management workflows.
User Roles
The system supports two primary roles:
Pastor - Can create churches, manage donations, and send communications
Member - Can join churches, make donations, and view information
User Registration
Register a New User
Create a new user account with email and password:
POST /api/auth/register
Content-Type : application/json
{
"email" : "[email protected] " ,
"password" : "securePassword123" ,
"role" : "member" ,
"invitedBy" : "[email protected] "
}
Registration Validation
The registration endpoint performs several validations:
Password Validation
Duplicate Email Check
Password Hashing
// Password must be at least 6 characters
if ( req . body . password . length < 6 ) {
return res . status ( 400 ). send ({
success: false ,
message: "Password must be at least 6 characters" ,
});
}
Success Response
{
"success" : true ,
"message" : "Registeration Successful" ,
"data" : "A verification link has been sent to you. Kindly verify your email address"
}
After registration, users must complete their profile before accessing full functionality. The isProfileComplete flag tracks this status.
User Authentication
Login Flow
Authenticate users and receive a JWT token:
POST /api/auth/login
Content-Type : application/json
{
"email" : "[email protected] " ,
"password" : "securePassword123"
}
Login Process
Email verification
The system first checks if a user exists with the provided email: const theUser = await authObject . findOne ({ email: body . email });
if ( ! theUser ) {
return res . status ( 404 ). send ({
success: false ,
message: "Log in not Successful" ,
data: `User with email ${ body . email } not found` ,
});
}
Password comparison
Compare the provided password with the hashed password: const isMatch = await bcrypt . compare ( body . password , theUser . password );
if ( ! isMatch ) {
return res . status ( 400 ). send ({
success: false ,
message: "Log in not Successful" ,
data: "Incorrect Email or Password" ,
});
}
JWT token generation
Generate a JWT token valid for 1 hour: const token = jwt . sign (
{ id: theUser . _id , role: theUser . role },
process . env . JWT_SECRET ,
{ expiresIn: "1h" }
);
Profile fetching
Retrieve the user’s profile information: const userProfile = await fetchProfileForLogin ( theUser . _id );
Login Response
{
"success" : true ,
"message" : "Login Successful" ,
"data" : {
"User" : {
"email" : "[email protected] " ,
"role" : "member" ,
"profile" : {
"_id" : "507f1f77bcf86cd799439011" ,
"name" : "John Doe" ,
"age" : 30 ,
"phoneNumber" : 1234567890
},
"invitedBy" : "[email protected] " ,
"isProfileComplete" : true ,
"createdAt" : "2024-01-15T10:30:00.000Z"
},
"token" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
}
Store the JWT token securely on the client side. Include it in the Authorization header for all authenticated requests: Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Profile Management
Create or Update Profile
Users must complete their profile after registration. This endpoint handles both creation and updates:
POST /api/users/createprofile
Authorization : Bearer <token>
Content-Type : application/json
{
"name" : "John Doe" ,
"address" : "123 Main St, City, State 12345" ,
"age" : 30 ,
"dob" : "1994-05-15" ,
"phoneNumber" : 1234567890
}
Profile Data Requirements
Field Type Validation Required nameString Any string Yes addressString Any string Yes ageNumber Min: 13, Max: 99 Yes dobDate Format: YYYY-MM-DD, must be past date Yes phoneNumberNumber Valid phone number Yes
Profile Creation Logic
const createOrUpdateProfile = async ( req , res ) => {
const userId = req . theUser . id ; // From JWT token
const profileData = req . body ;
try {
let profile = await profileObject . findOne ({ authDetails: userId });
if ( profile ) {
// Update existing profile
profile = await profileObject
. findOneAndUpdate ({ authDetails: userId }, { ... profileData })
. populate ( "authDetails" , "-password -_id -createdAt -updatedAt -__v" );
await authObject . findByIdAndUpdate ( userId , {
isProfileComplete: true ,
});
res . status ( 201 ). send ({
success: true ,
message: "Profile Updated" ,
data: profile ,
});
} else {
// Create new profile
profile = profileObject ({
authDetails: userId ,
... profileData ,
});
await profile . save ();
await authObject . findByIdAndUpdate ( userId , {
isProfileComplete: true ,
});
profile = await profileObject
. findById ( profile . _id )
. populate ( "authDetails" , "-password -_id -createdAt -updatedAt -__v" );
res . status ( 201 ). send ({
success: true ,
message: "Profile Created" ,
data: profile ,
});
}
} catch ( err ) {
res . status ( 500 ). send ({
success: false ,
message: "Profile Creation not successful" ,
data: err . message ,
});
}
};
Get User Profile
Retrieve the authenticated user’s profile information:
GET /api/users/getprofile
Authorization : Bearer <token>
Profile Response
{
"success" : true ,
"message" : "Profile found" ,
"data" : {
"_id" : "507f1f77bcf86cd799439011" ,
"name" : "John Doe" ,
"address" : "123 Main St, City, State 12345" ,
"age" : 30 ,
"dob" : "1994-05-15T00:00:00.000Z" ,
"phoneNumber" : 1234567890 ,
"authDetails" : {
"email" : "[email protected] " ,
"role" : "member" ,
"invitedBy" : "[email protected] " ,
"isProfileComplete" : true
}
}
}
Complete User Workflow
Here’s a typical user onboarding workflow:
Registration
User registers with email, password, and role: curl -X POST http://localhost:3001/api/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected] ",
"password": "securePass123",
"role": "member",
"invitedBy": "[email protected] "
}'
Login
User logs in and receives a JWT token: curl -X POST http://localhost:3001/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected] ",
"password": "securePass123"
}'
Save the token from the response.
Complete Profile
User completes their profile using the token: curl -X POST http://localhost:3001/api/users/createprofile \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-token>" \
-d '{
"name": "Jane Member",
"address": "456 Church Ave",
"age": 28,
"dob": "1996-03-20",
"phoneNumber": 5551234567
}'
Access Protected Resources
User can now access all features like joining churches and making donations.
Authentication Middleware
All protected endpoints require a valid JWT token. The middleware extracts the user ID from the token:
// Example of how the token is used in controllers
const userId = req . theUser . id ; // Populated by auth middleware
Always check isProfileComplete before allowing users to perform church-related actions. Users should complete their profiles first.
Error Handling
Common Error Responses
Registration Errors:
// Duplicate email
{
"success" : false ,
"message" : "Email already exists"
}
// Password too short
{
"success" : false ,
"message" : "Password must be at least 6 characters"
}
Login Errors:
// User not found
{
"success" : false ,
"message" : "Log in not Successful" ,
"data" : "User with email [email protected] not found"
}
// Wrong password
{
"success" : false ,
"message" : "Log in not Successful" ,
"data" : "Incorrect Email or Password"
}
Profile Errors:
// Profile not found
{
"success" : false ,
"message" : "Profile not found" ,
"data" : "You do not have any profile"
}
Security Best Practices
Important Security Considerations:
Passwords are hashed with bcrypt before storage (never stored in plain text)
JWT tokens expire after 1 hour
Emails are stored in lowercase for consistency
Email validation uses regex pattern matching
Role must be either “pastor” or “member”
Date of birth must be in the past
Age must be between 13-99 years
Next Steps