feat: enable Entra ID authentication

- Enable Better Auth middleware (was bypassed with return NextResponse.next())
- Re-enable AuthProvider in root layout
- Add public routes for webhooks, sync, kiosk, QBO, legal, health endpoints
- Set Microsoft Entra ID credentials and production Better Auth URLs
- Hide Engagement and Admin nav sections from non-super-admins
- Fix auth DB columns: snake_case → camelCase for Better Auth compatibility
- Add twoFactorEnabled column to user table
This commit is contained in:
lorentz 2026-03-17 08:49:20 -04:00
parent b98c67482a
commit 02c81bf4e4
3 changed files with 70 additions and 40 deletions

View file

@ -9,6 +9,28 @@ const publicRoutes = [
"/auth/2fa",
"/auth/setup",
"/api/auth",
// External service callbacks and webhooks
"/api/webhooks",
"/api/kiosk",
"/api/qbo/auth",
"/api/qbo/disconnect",
"/api/zabbix/webhook",
// Health and status checks
"/api/health",
"/api/integrations/status",
// Legal pages required by Intuit
"/legal",
// Sync endpoints called by scheduler
"/api/sync",
"/api/datto-rmm/sync",
"/api/itglue/sync",
"/api/veeam/sync",
"/api/sentinelone/sync",
"/api/engagement/sync",
"/api/zoom/sync",
"/api/qbo/sync",
"/api/reports/ticket-digest",
"/api/notifications/morning-summary/send",
];
// Routes that require admin or super-admin role
@ -17,44 +39,40 @@ const adminRoutes = ["/admin"];
export async function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// TEMPORARY: Authentication bypassed for private site access
// TODO: Re-enable authentication when site has public access
return NextResponse.next();
// Allow public routes
// if (publicRoutes.some((route) => pathname.startsWith(route))) {
// return NextResponse.next();
// }
if (publicRoutes.some((route) => pathname.startsWith(route))) {
return NextResponse.next();
}
// // Allow static files and API routes (except admin API)
// if (
// pathname.startsWith("/_next") ||
// pathname.startsWith("/favicon") ||
// pathname.includes(".")
// ) {
// return NextResponse.next();
// }
// Allow static files
if (
pathname.startsWith("/_next") ||
pathname.startsWith("/favicon") ||
pathname.includes(".")
) {
return NextResponse.next();
}
// // Check for session cookie
// const sessionCookie = getSessionCookie(request);
// Check for session cookie
const sessionCookie = getSessionCookie(request);
// if (!sessionCookie) {
// // Redirect to sign-in if no session
// const signInUrl = new URL("/auth/sign-in", request.url);
// signInUrl.searchParams.set("callbackUrl", pathname);
// return NextResponse.redirect(signInUrl);
// }
if (!sessionCookie) {
// Redirect to sign-in if no session
const signInUrl = new URL("/auth/sign-in", request.url);
signInUrl.searchParams.set("callbackUrl", pathname);
return NextResponse.redirect(signInUrl);
}
// // For admin routes, we need to verify the role
// // This is a basic check - the actual role verification happens in the API routes
// if (adminRoutes.some((route) => pathname.startsWith(route))) {
// // The session cookie exists, but we can't decode it here without the secret
// // Role-based access control is enforced at the API level
// // This middleware just ensures there's a session
// return NextResponse.next();
// }
// For admin routes, we need to verify the role
// This is a basic check - the actual role verification happens in the API routes
if (adminRoutes.some((route) => pathname.startsWith(route))) {
// The session cookie exists, but we can't decode it here without the secret
// Role-based access control is enforced at the API level
// This middleware just ensures there's a session
return NextResponse.next();
}
// return NextResponse.next();
return NextResponse.next();
}
export const config = {