import { NextRequest, NextResponse } from 'next/server'; const config = { matcher: [ /* * Match all paths except for: * 1. /api routes * 2. /_next (Next.js internals) * 3. /_static (inside /public) * 4. all root files inside /public (e.g. /favicon.ico) */ '/((?!api/|_next/|_static/|_vercel|[\\w-]+\\.\\w+).*)', ], }; export default async function middleware(req: NextRequest) { const url = req.nextUrl; const response = NextResponse.next(); // Maximum size to prevent cookie chunking - make it even more conservative const MAX_COOKIE_SIZE = 3000; // even more conservative limit in bytes // Function to set all required nextAuth environment variables const setNextAuthEnvVars = () => { // Set strict cookie size limits process.env.NEXTAUTH_COOKIE_SIZE_LIMIT = String(MAX_COOKIE_SIZE); // Force cookie compression to reduce size process.env.NEXTAUTH_COOKIES_CHUNKING = 'false'; // Disable chunking and force smaller cookies process.env.NEXTAUTH_COOKIES_CHUNKING_SIZE = String(MAX_COOKIE_SIZE); // Set secure cookie settings process.env.NEXTAUTH_COOKIES_SECURE = 'true'; process.env.NEXTAUTH_COOKIES_SAMESITE = 'none'; // Disable unnecessary callbacks that might increase cookie size process.env.NEXTAUTH_DISABLE_CALLBACK = 'true'; process.env.NEXTAUTH_DISABLE_JWT_CALLBACK = 'true'; process.env.NEXTAUTH_JWT_STORE_RAW_TOKEN = 'false'; // Strongly enforce JWT max age process.env.NEXTAUTH_JWT_MAX_AGE = String(12 * 60 * 60); // 12 hours in seconds }; // Set environment variables for all routes setNextAuthEnvVars(); // Detect refresh token errors in cookies and clean them up const checkForErrorsAndCleanup = () => { const cookies = req.cookies; const cookieNames = Object.keys(cookies.getAll()); // Check for error param in URL that would indicate token refresh errors if (url.pathname.includes('/signin') && url.searchParams.has('error')) { // Clean up all auth cookies to ensure a fresh start const allAuthCookies = cookieNames.filter(name => name.includes('auth') || name.includes('keycloak') || name.includes('session') || name.includes('KEYCLOAK') || name.includes('KC_') ); allAuthCookies.forEach(name => { response.cookies.delete(name); }); // Special header to indicate a serious error that requires full cleanup response.headers.set('X-Auth-Error-Recovery', 'true'); } }; // Check for and clean up error cookies checkForErrorsAndCleanup(); // Special handling for loggedout page to clean up cookies if (url.pathname === '/loggedout') { // Check if we're preserving SSO or doing a full logout const preserveSso = url.searchParams.get('preserveSso') === 'true'; console.log(`Middleware detected logout (preserveSso: ${preserveSso})`); if (preserveSso) { // Only clean up NextAuth cookies but preserve Keycloak SSO cookies const nextAuthCookies = [ 'next-auth.session-token', 'next-auth.csrf-token', 'next-auth.callback-url', '__Secure-next-auth.session-token', '__Host-next-auth.csrf-token' ]; nextAuthCookies.forEach(name => { response.cookies.delete(name); }); // Also delete any chunked cookies const cookieNames = Object.keys(req.cookies.getAll()); const chunkedCookies = cookieNames.filter(name => /next-auth.*\.\d+$/.test(name)); chunkedCookies.forEach(name => { response.cookies.delete(name); }); } else { // Full logout - clear all auth-related cookies const authCookies = [ 'next-auth.session-token', 'next-auth.csrf-token', 'next-auth.callback-url', '__Secure-next-auth.session-token', '__Host-next-auth.csrf-token', 'KEYCLOAK_SESSION', 'KEYCLOAK_IDENTITY', 'KC_RESTART', 'JSESSIONID' ]; authCookies.forEach(name => { response.cookies.delete(name); }); // Also delete any chunked cookies const cookieNames = Object.keys(req.cookies.getAll()); const chunkedCookies = cookieNames.filter(name => /next-auth.*\.\d+$/.test(name) || /KEYCLOAK.*/.test(name) || /KC_.*/.test(name) ); chunkedCookies.forEach(name => { response.cookies.delete(name); }); } } // For sign-in page, add header if fresh login is requested if (url.pathname === '/api/auth/signin' && url.searchParams.get('fresh') === 'true') { response.headers.set('X-Auth-Fresh-Login', 'true'); } return response; } export { config };