Neah/middleware.ts
2025-05-02 12:56:20 +02:00

142 lines
4.7 KiB
TypeScript

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 };