A full‑stack, secure digital election and polling platform designed for universities and institutions. It demonstrates and enforces strong security controls: multi‑factor authentication, JWT‑based sessions, layered access control (RBAC, DAC, RuBAC, ABAC, MAC), comprehensive auditing, and backup/restore.
The system is not intended to replace real national elections. Its goal is to teach and showcase security concepts while remaining usable for real student elections and internal polls.
-
Multi‑role access model
Admin– manages users, roles, system configuration, and backups.Election Officer– creates and manages elections, delegates assistants.Voter– views eligible elections and casts votes.Auditor– reviews logs and verifies election integrity.
-
Strong authentication & account lifecycle
- Email/password login with strong password policy (12+ chars, complexity).
- Email / OTP verification on registration.
- Optional MFA/OTP (via
speakeasy). - JWT access & refresh tokens; lockout on repeated failures.
-
Layered access control (policy engine)
- RBAC – routes and actions restricted by role.
- DAC – election officers can delegate/manage assistants per election.
- RuBAC (time‑based) – elections only open within configured time windows.
- ABAC – eligibility rules (e.g., age, region, verification status).
- MAC – vote data treated as confidential; results classification changes after publishing.
-
Secure election workflow
- Create elections with title, description, options, and start/end times.
- Officers see only their own elections in “My Elections”.
- Voters see only elections they are eligible for and cannot double‑vote.
- Voting is allowed only inside the configured window.
- Live results hidden from voters while an election is active; only final results are revealed.
-
Auditing & monitoring
- Every major action (login, role change, election creation, vote, permission change) is logged.
Auditordashboard to search/filter logs.- Alerts for suspicious behavior (e.g., repeated failed logins).
-
Resilience & backups
- PostgreSQL schema for users, elections, votes, permissions, audit logs.
- Scheduled DB backups; restore process for disaster recovery.
Frontend
- React (Vite)
- React Router, React Context for auth
- Tailwind CSS for styling
- Axios for HTTP
- React‑Toastify for notifications
- Framer Motion for simple modals/animations
Backend
- Node.js + Express
- PostgreSQL via
pg - JWT (
jsonwebtoken) and refresh tokens bcryptjsfor password hashinghelmet,cors,express-rate-limitfor API hardeningnodemailer(and optionally SMS/email integrations) for verification/MFAwinstonfor structured logging
Database
- PostgreSQL with schema defined in
backend/database/schema.sql.
.
├── backend/ # Node/Express API + security logic
│ ├── server.js # Express app entry point
│ ├── package.json
│ ├── database/
│ │ └── schema.sql # PostgreSQL schema
│ ├── controllers/ # Route handlers (auth, admin, elections/polls)
│ ├── middleware/ # JWT, RBAC, policy engine, auditing
│ ├── routes/ # Express route definitions
│ └── src/ # Refactored/structured backend code
│ ├── config/
│ ├── controllers/
│ ├── middleware/
│ ├── routes/
│ └── utils/
│
├── frontend/ # React + Tailwind SPA
│ ├── src/
│ │ ├── pages/ # Role‑based pages & dashboards
│ │ ├── layouts/
│ │ ├── context/ # AuthContext
│ │ ├── services/ # API wrappers
│ │ └── api/ # Axios instance
│ ├── public/
│ └── package.json
│
└── README.md # You are here
- Users register with email/password and must verify their account before logging in.
- Passwords are hashed with bcrypt; plain text passwords are never stored.
- Login returns a short‑lived access token and long‑lived refresh token.
- Optional MFA using OTP (e.g., TOTP via
speakeasy). - Accounts are locked for a period after repeated failed logins.
Requests pass through a chain of middleware:
- JWT verification (auth middleware) – ensures the user is authenticated.
- RBAC – checks the user’s role before accessing specific routes.
- RuBAC (time‑based) – ensures elections are only open during configured windows.
- ABAC – checks attributes like age, region, verification flags, and eligibility.
- MAC – enforces data classification; for votes, only aggregated results are exposed.
- DAC (per‑election permissions) – allows owners to grant/revoke assistants on their elections.
This layered model prevents unauthorized actions even if one piece is misconfigured.
- Each election has an owner (the officer who created it).
- Owners can grant assistants permission to view or manage that specific election.
- Assistants appear in the Officer dashboard and can perform only the delegated actions.
- All DAC changes (grant/revoke) are logged to the audit log.
- Voters see only elections that:
- Match their attributes (e.g., region, age)
- Are in the open voting window
- They have not voted in before
- The database enforces one vote per user per election (unique constraints).
- Votes are stored confidentially; only aggregated counts are used for results.
- During the active period, voters do not see live result tallies.
- All sensitive actions are written to an
audit_logstable with user id, action, IP, and timestamp. - The Auditor role can query and filter logs in their dashboard.
- Nightly (or scheduled) backups of the PostgreSQL database are taken and verified.
- Node.js (LTS)
- npm or yarn
- PostgreSQL instance (local Docker or remote)
git clone https://github.com/your-username/Secure-Voting-System.git
cd Secure-Voting-Systemcd backend
npm installCreate a .env file in backend/ (example):
cp .env.example .env # if provided, otherwise create manuallyTypical environment variables (adapt to your setup):
PORT=5000
DATABASE_URL=postgres://user:password@localhost:5432/secure_voting
JWT_SECRET=super_long_random_secret
REFRESH_TOKEN_SECRET=another_super_long_random_secret
EMAIL_HOST=smtp.example.com
EMAIL_PORT=587
EMAIL_USER=your_email@example.com
EMAIL_PASS=your_email_password
FRONTEND_URL=http://localhost:5173Initialize the PostgreSQL schema using backend/database/schema.sql.
Then run the backend server (development):
cd backend
npm run devThe API will typically run on http://localhost:5000.
In another terminal:
cd frontend
npm install
npm run devThe React app will run on something like http://localhost:5173 (Vite default).
Make sure the frontend Axios base URL matches your backend URL (see frontend/src/api/axios.js).
- User registers with email + strong password + CAPTCHA.
- System creates user with
role = NULL,is_verified = falseand sends verification (email or OTP). - After verification, the user can log in but is redirected to Pending Approval until an Admin assigns a role.
- Admin logs in and opens the Admin Dashboard.
- Reviews new users and assigns roles (Voter, Officer, Auditor, etc.).
- Can view basic system stats, backup status, and audit logs.
- Officer logs in and opens the Officer Dashboard.
- Creates new elections with title, description, options, start/end times, and eligibility rules.
- Sees only their own elections under “My Elections”.
- Can edit active/future elections (within allowed constraints).
- Can manage assistants for specific elections via DAC.
- After an election closes, can publish results.
- Voter logs in and opens the Voter Dashboard.
- Sees a list of eligible and open elections with countdowns.
- Opens an election, selects a candidate/option, and submits their vote.
- Gets confirmation; cannot vote again for the same election.
- Auditor logs in and opens the Auditor Dashboard.
- Filters/searches
audit_logsby user, action, time range. - Reviews final results and checks for anomalies.
- Always run behind HTTPS (reverse proxy like Nginx or a cloud load balancer).
- Store secrets (JWT keys, DB creds, SMTP creds) in a secure secret manager.
- Configure rate limiting on login and sensitive endpoints.
- Harden CORS to only allow trusted frontend origins.
- Ensure backups are encrypted and tested regularly.
- Rotate JWT secrets and refresh tokens on schedule.
- Fork the repository and create a feature branch.
- Make your changes, following existing code style and structure.
- Add or update documentation if you introduce new behavior.
- Open a Pull Request with a clear description of your changes.
This project is intended for educational and institutional use. Add an explicit license here if you plan to open‑source or distribute it.