This repository contains the backend API for the university election portal system. The API provides endpoints for user authentication, election management, grievance handling, and voting.
- Multi-role authentication (Admin, House, Society, User)
- Access control based on user roles
- Election management for university, houses, and societies
- Candidate nomination and approval
- Voting system
- Grievance submission and resolution
- Results calculation and display
- Node.js (v14 or higher)
- MongoDB
- NPM or Yarn
- Clone the repository
git clone <repository-url>
cd election-portal-backend- Install dependencies
npm install- Create environment variables
cp .env.example .env-
Edit the
.envfile with your configuration -
Start the development server
npm run devThe backend implements several security measures:
-
JWT-based Authentication
- Secure tokens for session management
- Token refresh mechanism
- Automatic token expiration
-
Role-Based Access Control
- Different permission levels (Admin, House, Society, User)
- Resource-specific authorization checks
-
Data Protection
- Password hashing with bcrypt
- Sensitive data hiding in API responses
-
Request Validation
- Input validation for all endpoints
- Prevention of common attacks (injection, XSS)
-
Rate Limiting
- Protection against brute force attacks
- API abuse prevention
-
Secure HTTP Headers
- Helmet.js implementation for security headers
- CORS configuration
| Method | Endpoint | Description | Access |
|---|---|---|---|
| POST | /api/auth/signup |
Register a new user | Public |
| POST | /api/auth/login |
Log in a user | Public |
| POST | /api/auth/refresh-token |
Refresh access token | Public |
| PATCH | /api/auth/update-password |
Update user password | Authenticated |
| Method | Endpoint | Description | Access |
|---|---|---|---|
| GET | /api/users/me |
Get current user profile | Authenticated |
| PATCH | /api/users/me |
Update current user profile | Authenticated |
| GET | /api/users |
Get all users | Admin |
| GET | /api/users/:id |
Get specific user | Admin |
| PATCH | /api/users/:id |
Update user | Admin |
| DELETE | /api/users/:id |
Delete user | Admin |
| Method | Endpoint | Description | Access |
|---|---|---|---|
| GET | /api/elections |
Get all elections | Authenticated |
| GET | /api/elections/:id |
Get election details | Authenticated |
| POST | /api/elections |
Create a new election | Admin, House, Society |
| PATCH | /api/elections/:id |
Update an election | Admin, Election Creator |
| DELETE | /api/elections/:id |
Delete an election | Admin, Election Creator |
| POST | /api/elections/:id/position |
Add a position to election | Admin, Election Creator |
| POST | /api/elections/:id/nominate |
Submit a nomination | Authenticated |
| PATCH | /api/elections/:id/approve-nomination |
Approve a nomination | Admin, House, Society |
| Method | Endpoint | Description | Access |
|---|---|---|---|
| GET | /api/houses |
Get all houses | Authenticated |
| GET | /api/houses/:id |
Get house details | Authenticated |
| POST | /api/houses |
Create a new house | Admin |
| PATCH | /api/houses/:id |
Update house | Admin |
| DELETE | /api/houses/:id |
Delete house | Admin |
| POST | /api/houses/:id/members |
Add members to house | Admin |
| DELETE | /api/houses/:id/members/:userId |
Remove member from house | Admin |
| Method | Endpoint | Description | Access |
|---|---|---|---|
| GET | /api/societies |
Get all societies | Authenticated |
| GET | /api/societies/:id |
Get society details | Authenticated |
| POST | /api/societies |
Create a new society | Admin |
| PATCH | /api/societies/:id |
Update society | Admin, Society Lead |
| DELETE | /api/societies/:id |
Delete society | Admin |
| POST | /api/societies/:id/members |
Add members to society | Admin, Society Lead |
| DELETE | /api/societies/:id/members/:userId |
Remove member from society | Admin, Society Lead |
| Method | Endpoint | Description | Access |
|---|---|---|---|
| GET | /api/grievances |
Get all grievances | Admin |
| GET | /api/grievances/my |
Get user's grievances | Authenticated |
| GET | /api/grievances/:id |
Get grievance details | Admin, Grievance Creator |
| POST | /api/grievances |
Submit a grievance | Authenticated |
| PATCH | /api/grievances/:id |
Update grievance status | Admin |
| POST | /api/grievances/:id/resolve |
Resolve a grievance | Admin |
| Method | Endpoint | Description | Access |
|---|---|---|---|
| POST | /api/votes/:electionId |
Cast a vote | Authenticated |
| GET | /api/votes/my |
Get user's voting history | Authenticated |
| Method | Endpoint | Description | Access |
|---|---|---|---|
| GET | /api/results/:electionId |
Get election results | Authenticated |
// Login request
const login = async (email, password) => {
try {
const response = await fetch('http://localhost:3000/api/auth/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ email, password })
});
const data = await response.json();
if (data.status === 'success') {
// Store tokens securely
localStorage.setItem('token', data.token);
localStorage.setItem('refreshToken', data.refreshToken);
return data.data.user;
} else {
throw new Error(data.message);
}
} catch (error) {
console.error('Login error:', error);
throw error;
}
};// Function to make authenticated API requests
const authFetch = async (url, options = {}) => {
const token = localStorage.getItem('token');
// Set authorization header
const authOptions = {
...options,
headers: {
...options.headers,
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
};
try {
const response = await fetch(url, authOptions);
// Handle 401 Unauthorized (token expired)
if (response.status === 401) {
const refreshed = await refreshAccessToken();
if (refreshed) {
// Retry with new token
return authFetch(url, options);
} else {
// Redirect to login if refresh failed
window.location.href = '/login';
throw new Error('Session expired. Please log in again.');
}
}
return response;
} catch (error) {
console.error('API request error:', error);
throw error;
}
};
// Function to refresh access token
const refreshAccessToken = async () => {
const refreshToken = localStorage.getItem('refreshToken');
if (!refreshToken) return false;
try {
const response = await fetch('http://localhost:3000/api/auth/refresh-token', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ refreshToken })
});
const data = await response.json();
if (data.status === 'success') {
localStorage.setItem('token', data.token);
return true;
} else {
return false;
}
} catch (error) {
console.error('Token refresh error:', error);
return false;
}
};// Get all elections
const getElections = async () => {
try {
const response = await authFetch('http://localhost:3000/api/elections');
const data = await response.json();
if (data.status === 'success') {
return data.data.elections;
} else {
throw new Error(data.message);
}
} catch (error) {
console.error('Error fetching elections:', error);
throw error;
}
};
// Get specific election details
const getElectionDetails = async (electionId) => {
try {
const response = await authFetch(`http://localhost:3000/api/elections/${electionId}`);
const data = await response.json();
if (data.status === 'success') {
return data.data.election;
} else {
throw new Error(data.message);
}
} catch (error) {
console.error('Error fetching election details:', error);
throw error;
}
};// Cast a vote in an election
const castVote = async (electionId, positionTitle, candidateId) => {
try {
const response = await authFetch(`http://localhost:3000/api/votes/${electionId}`, {
method: 'POST',
body: JSON.stringify({
position: positionTitle,
candidate: candidateId
})
});
const data = await response.json();
if (data.status === 'success') {
return true;
} else {
throw new Error(data.message);
}
} catch (error) {
console.error('Error casting vote:', error);
throw error;
}
};-
Never store the JWT token in cookies or localStorage in a production environment. Consider using HttpOnly cookies or a more secure storage mechanism.
-
Implement proper CSRF protection for cookie-based authentication.
-
Validate all user inputs on both client and server sides.
-
Use HTTPS for all API communications in production.
-
Implement proper error handling without exposing sensitive information.
-
Set appropriate CORS policies in production to restrict access to trusted domains.
-
Regularly rotate and refresh tokens to reduce the impact of token theft.
-
Implement two-factor authentication for sensitive operations like changing password or voting.
[Your License Here]