80 lines
2.4 KiB
TypeScript
80 lines
2.4 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import { getSessionCookie } from "better-auth/cookies";
|
|
|
|
/**
|
|
* Middleware for protecting authenticated routes
|
|
*
|
|
* Best practices from Better Auth:
|
|
* - Use getSessionCookie for optimistic cookie-based session check
|
|
* - Handle redirects properly with intent preservation
|
|
* - Exclude public routes and API routes
|
|
* - Don't perform RBAC here (do it at page level with database access)
|
|
*
|
|
* Note: This is an OPTIMISTIC check (cookie existence only)
|
|
* Full session validation happens at the page level using auth.api.getSession()
|
|
*
|
|
* Protected routes:
|
|
* - /admin/* - Admin panel (role check in page)
|
|
* - /dentist/* - Dentist portal (role check in page)
|
|
* - /patient/* - Patient portal (role check in page)
|
|
* - /profile/* - User profile (any authenticated user)
|
|
*/
|
|
export async function middleware(request: NextRequest) {
|
|
const pathname = request.nextUrl.pathname;
|
|
|
|
// Skip middleware for API routes and public paths
|
|
if (
|
|
pathname.startsWith("/api/auth") ||
|
|
pathname.startsWith("/_next") ||
|
|
pathname.startsWith("/static")
|
|
) {
|
|
return NextResponse.next();
|
|
}
|
|
|
|
// Optimistic cookie-based session check
|
|
// This only checks for cookie existence, not validity
|
|
// Full validation happens at the page level
|
|
// CRITICAL: Must pass cookiePrefix to match auth.ts configuration
|
|
const sessionCookie = getSessionCookie(request, {
|
|
cookiePrefix: "better-auth", // Must match advanced.cookiePrefix in auth.ts
|
|
});
|
|
|
|
// No session cookie - redirect to sign-in
|
|
if (!sessionCookie) {
|
|
if (process.env.NODE_ENV === "development") {
|
|
console.log("[Middleware] No session cookie found for:", pathname);
|
|
}
|
|
|
|
const signInUrl = new URL("/sign-in", request.url);
|
|
signInUrl.searchParams.set("from", pathname);
|
|
return NextResponse.redirect(signInUrl);
|
|
}
|
|
|
|
// Session cookie exists - allow access
|
|
// Note: RBAC is handled at the page level where we have database access
|
|
const response = NextResponse.next();
|
|
|
|
// Prevent caching of authenticated pages
|
|
response.headers.set(
|
|
"Cache-Control",
|
|
"no-store, no-cache, must-revalidate, proxy-revalidate"
|
|
);
|
|
response.headers.set("Pragma", "no-cache");
|
|
response.headers.set("Expires", "0");
|
|
|
|
return response;
|
|
}
|
|
|
|
export const config = {
|
|
matcher: [
|
|
"/admin/:path*",
|
|
"/admin",
|
|
"/dentist/:path*",
|
|
"/dentist",
|
|
"/patient/:path*",
|
|
"/patient",
|
|
"/profile/:path*",
|
|
"/profile",
|
|
],
|
|
};
|