Authentication & Role-Based Access Control (RBAC)
Identity management, session validation, and permissions across veridex-hitech-web-application are governed by NextAuth.js v5 (Auth.js beta) configured with custom Credentials providers, JWT session strategies, and strict server-side Role-Based Access Control (RBAC).
1. Authentication Architecture: NextAuth v5 & JWT Strategy
1.1 Why Credentials + JWT Strategy?
In Next.js App Router, global route protection runs in middleware.ts on the Edge Runtime.
- Mongoose and MongoDB drivers cannot open raw TCP sockets on Edge. A database session strategy would fail in middleware on every route access.
- The JWT Strategy cryptographically signs and encrypts session data directly into the HTTP-only cookie (
authjs.session-token). middleware.tsinspects cookie presence instantly in sub-5ms without opening database connections.
1.2 Custom Token Expiration Claims (src/lib/auth.ts)
Standard NextAuth sessions expire on a static interval. The platform enriches the JWT callback with a dynamic customExp claim based on the user's "Remember Me" selection:
// Session Expiration Logic in src/lib/auth.ts
async jwt({ token, user }) {
if (token.customExp && Date.now() > (token.customExp as number)) {
return null as any; // Token has expired based on custom logic
}
if (user) {
token.id = user.id;
token.role = user.role;
token.firstName = user.firstName;
token.lastName = user.lastName;
token.referralCode = user.referralCode;
token.isEmailVerified = user.isEmailVerified;
// 14 days if rememberMe is true, otherwise 24 hours
const expirationMs = user.rememberMe
? 14 * 24 * 60 * 60 * 1000
: 24 * 60 * 60 * 1000;
token.customExp = Date.now() + expirationMs;
}
return token;
}
2. Role-Based Access Control (RBAC) Hierarchy
The platform defines three strictly segregated user roles stored in User.role:
| Role | Access Level | Permitted Operations & Routes |
|---|---|---|
super_admin | System Owner | Unrestricted platform access: create and remove administrator accounts, view raw security audit logs (AdminAuditLog), update API credentials, and trigger database maintenance. Exactly one super-admin is allowed across the database. |
admin | Agency Staff | Back-office control center (/admin): inspect and export customer quote leads, review claims and careers, run mass bulk email campaigns, author Tiptap blogs and dynamic FAQs, manage QR event campaigns, and resolve failed CRM leads. |
user | Customer / Affiliate | Personal customer portal (/dashboard): profile management, interactive avatar photo cropping, incomplete quote draft resumption, submission audit history, and Refer & Earn rewards tracking. |
3. Server-Side Guard Helpers (src/lib/auth-helpers.ts)
Server Actions must never rely solely on client assertions. All protected mutations execute server-side verification:
// Pattern: Server Action RBAC Protection
export async function requireAuth(): Promise<Session> {
const session = await auth();
if (!session || !session.user) {
throw new Error("UNAUTHORIZED");
}
return session;
}
export async function requireAdmin(): Promise<Session> {
const session = await requireAuth();
if (session.user.role !== "admin" && session.user.role !== "super_admin") {
throw new Error("FORBIDDEN_ADMIN_REQUIRED");
}
return session;
}
export async function requireSuperAdmin(): Promise<Session> {
const session = await requireAuth();
if (session.user.role !== "super_admin") {
throw new Error("FORBIDDEN_SUPER_ADMIN_REQUIRED");
}
return session;
}
4. Administrative 404 Security Cloaking
A common flaw in web applications is redirecting unauthenticated users from /admin to /sign-in. This confirms to malicious scanners that an administrative panel exists at that route.
The platform implements 404 Security Cloaking in src/app/[locale]/admin/page.tsx:
// Pattern: 404 Security Cloaking on /admin
export default async function AdminPage({ params }: AdminPageProps) {
await params;
const session = await auth();
if (!session || (session.user.role !== "admin" && session.user.role !== "super_admin")) {
// Completely cloaks the admin panel from non-admins and scanners
notFound();
}
return <AdminDashboard userRole={session.user.role} initialUser={session.user} />;
}
Non-administrative users and bots accessing /admin receive a standard HTTP 404 Not Found response, completely concealing the existence of the administrative portal.
5. User Profile & Avatar Upload Security
5.1 Profile Locking (profileLocked)
To prevent unauthorized account takeovers or manipulation of referral reward payouts, sensitive profile fields (email, phone, referralCode) can be locked via the profileLocked flag on the User document. Once locked, modifications through PATCH /api/user/profile are rejected with HTTP 403 Forbidden.
5.2 Avatar Upload Verification (POST /api/user/profile/avatar)
- Format Whitelist: Strictly permits
image/png,image/jpeg, andimage/webp. Executables and SVG files (which can contain embedded XSS scripts) are rejected. - Payload Size Capping: Enforces a maximum payload limit of 2 MB to protect database memory and connection bandwidth.
- Canvas Sanitization: The client component (
ImageCropModal) rasterizes the image onto an off-screen HTML5 canvas element before base64 encoding, stripping malicious EXIF metadata.
6. Swagger & OpenAPI Documentation Password Gate
Interactive API documentation routes (/api/docs and /api/docs/openapi.json) expose the system's entire RESTful attack surface:
- Authentication Route (
POST /api/docs/auth): Receives a password string and compares it againstSWAGGER_DOCS_PASSWORD_HASHusingbcrypt.compare. - Session Token: On success, sets an HTTP-only secure cookie named
hti_swagger_tokencontaining a cryptographically signed HMAC token. - Locking Session (
DELETE /api/docs/auth): Immediately expires the cookie, locking the documentation explorer. - Brute-Force Shield: Protected under the
AUTH_STRICTrate limit tier (maximum 5 attempts per 15 minutes).