fitaiProto/apps/admin/src/middleware.ts
2026-03-10 04:14:03 +01:00

62 lines
1.9 KiB
TypeScript

import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server";
import { validateEnv } from "./lib/env";
import log from "./lib/logger";
// Validate environment variables on server startup
try {
validateEnv();
log.info("Environment validation passed");
} catch (error) {
log.error("Environment validation failed", error);
// Re-throw to prevent server from starting with invalid config
throw error;
}
// Define routes that should be publicly accessible (no auth required)
const isPublicRoute = createRouteMatcher([
"/sign-in(.*)",
"/sign-up(.*)",
"/api/webhooks(.*)",
"/api/health(.*)",
]);
// Define API routes that need auth but should be handled in the route itself
// This prevents auth.protect() from blocking before the route handler runs
const isApiRoute = createRouteMatcher(["/api/(.*)"]);
export default clerkMiddleware(async (auth, req) => {
// Log for debugging
const authHeader = req.headers.get("authorization");
if (authHeader) {
log.debug("Authorization header present", {
preview: authHeader.substring(0, 20) + "...",
});
}
// Don't protect public routes
if (isPublicRoute(req)) {
log.debug("Public route, skipping auth");
return;
}
// For API routes, let the route handler check auth
// This allows API routes to handle both web sessions and mobile Bearer tokens
if (isApiRoute(req)) {
log.debug("API route, auth will be checked in handler");
return;
}
// For all other routes (web pages), enforce authentication
log.debug("Protected route, requiring auth");
await auth.protect();
});
export const config = {
matcher: [
// Skip Next.js internals and all static files, unless found in search params
"/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)",
// Always run for API routes
"/(api|trpc)(.*)",
],
};