TrueCert is a production-ready full-stack SaaS application for secure digital certificate issuance and public verification.
- JWT-based issuer authentication
- Certificate creation with unique certificate IDs
- SHA-256 tamper detection signature
- QR generation mapped to public verification URLs
- PDF generation and Cloudinary upload
- Public verify route with revocation and expiry handling
- Scan analytics with device/browser/location metadata
- Screenshot-resistance helpers (dynamic watermark, right-click and shortcut hardening, protected viewer)
- Responsive, modern React dashboard and landing pages
- Frontend: React, Vite, Tailwind CSS, React Router DOM, Axios, Framer Motion, Recharts, React Icons, React Share
- Backend: Node.js, Express.js, Mongoose
- Database: MongoDB Atlas
- Storage: Cloudinary
- Deploy: Vercel (frontend), Render (backend)
./
frontend/
backend/
README.md
.gitignore
render.yaml
Use backend/.env.example.
PORT=5000
MONGODB_URI=
JWT_SECRET=
CLOUDINARY_CLOUD_NAME=
CLOUDINARY_API_KEY=
CLOUDINARY_API_SECRET=
FRONTEND_URL=http://localhost:5173
PDF_ACCESS_TOKEN_TTL_MINUTES=10VITE_API_BASE_URL=http://localhost:5000/apicd backend
npm install
cd ../frontend
npm install- Create backend
.envfrombackend/.env.example - Create frontend
.envfromfrontend/.env.example
cd backend
npm run devcd frontend
npm run devFrontend default: http://localhost:5173
Backend default: http://localhost:5000
Base URL: /api
-
POST /auth/register- body:
name,email,password,organization - response:
token,user
- body:
-
POST /auth/login- body:
email,password - response:
token,user
- body:
-
GET /auth/me- auth: Bearer token
- response: authenticated
user
-
POST /certificates- auth: Bearer token
- content-type:
multipart/form-data - fields:
candidateNamecertificateTitlecourseNameissueDateexpiryDate(optional)issuerNamegrade(optional)description(optional)logofile (optional)signaturefile (optional)
- creates certificate, generates QR/PDF, uploads media to Cloudinary
-
GET /certificates- auth: Bearer token
- query:
search(optional) - response: all issuer certificates
-
GET /certificates/summary/dashboard- auth: Bearer token
- response:
totalCertificatesactiveCertificatesrevokedCertificatesexpiredCertificatestotalScanslastIssuedCertificaterecentActivity
-
GET /certificates/:certificateId- auth: Bearer token
- response: specific certificate
-
PATCH /certificates/:certificateId/revoke- auth: Bearer token
- response: revoked certificate record
-
GET /verify/:certificateId- public route
- logs scan metadata and returns verification payload
- returns:
- certificate fields
verification.isAuthenticverification.message
-
GET /verify/:certificateId/pdf?token=<signed>&sessionId=<optional>- public route with signed short-lived token
- validates token type, certificate match, token freshness, and optional session binding
- redirects to certificate PDF URL if valid
GET /analytics- auth: Bearer token
- returns:
totalScansscansPerDaytopCertificatesrecentScans
helmethardening for HTTP headers- rate limiting (
express-rate-limit) - endpoint-level limiters for auth, issue, and verify flows
- JWT auth middleware
- bcrypt password hashing
- SHA-256 certificate hash signature check
- NoSQL-style request sanitization middleware for body/query/params
- signed short-lived PDF access tokens with optional session binding
- uploaded image binary signature verification (PNG/JPEG/WEBP)
- CORS allowlist from
FRONTEND_URL - Screenshot-resistance enhancements in verification UI
- Root:
frontend - Build command:
npm run build - Output directory:
dist - Add env var:
VITE_API_BASE_URL=https://<render-backend-domain>/api frontend/vercel.jsonalready rewrites client routes toindex.html
- Use
render.yamlat repo root - Service root directory:
backend - Add production env vars in Render dashboard
- Ensure
FRONTEND_URLequals deployed Vercel domain
- Add production connection string to
MONGODB_URI - Whitelist Render outbound IPs or allow broader access with strong auth
- Use secure credentials and HTTPS-only URLs
Run after configuration:
cd frontend
npm run build
cd ../backend
npm run check