diff --git a/frontend/src/middleware.ts b/frontend/src/middleware.ts index cde3ed1..88a62b5 100644 --- a/frontend/src/middleware.ts +++ b/frontend/src/middleware.ts @@ -47,18 +47,103 @@ function getLocale(request: NextRequest): string | undefined { } } +/** + * Check if user is authenticated by verifying auth token in cookies + */ +function isAuthenticated(request: NextRequest): boolean { + const authToken = request.cookies.get('auth_token'); + const sessionToken = request.cookies.get('session_token'); + + // Check for either auth_token or session_token + // You can customize this based on your authentication mechanism + return !!(authToken || sessionToken); +} + +/** + * Extract locale from pathname + */ +function extractLocale(pathname: string): string | null { + const localeRegex = new RegExp(`^/(${i18n.locales.join('|')})`); + const match = pathname.match(localeRegex); + return match ? match[1] : null; +} + +/** + * Get pathname without locale prefix + */ +function getPathnameWithoutLocale(pathname: string): string { + const locale = extractLocale(pathname); + if (locale) { + return pathname.replace(`/${locale}`, '') || '/'; + } + return pathname; +} + +/** + * Check if path is a public route (doesn't require authentication) + */ +function isPublicRoute(pathname: string): boolean { + const pathWithoutLocale = getPathnameWithoutLocale(pathname); + + // Public routes that don't require authentication + const publicRoutes = [ + '/login', + '/signup', + '/register', + '/forgot-password', + '/reset-password', + ]; + + // Check if path starts with any public route + return publicRoutes.some(route => pathWithoutLocale.startsWith(route)); +} + +/** + * Check if path is a protected route (requires authentication) + * By default, all routes are protected except explicitly public ones + */ +function isProtectedRoute(pathname: string): boolean { + const pathWithoutLocale = getPathnameWithoutLocale(pathname); + + // If it's a public route, it's not protected + if (isPublicRoute(pathname)) { + return false; + } + + // All other routes (dashboard routes, home, etc.) are protected by default + // This includes: /, /my_books, /books, /profile, /settings, etc. + return true; +} + export function middleware(request: NextRequest) { const pathname = request.nextUrl.pathname; + const authenticated = isAuthenticated(request); + const locale = extractLocale(pathname) || getLocale(request) || i18n.defaultLocale; + const pathWithoutLocale = getPathnameWithoutLocale(pathname); + const isPublic = isPublicRoute(pathname); + const isProtected = isProtectedRoute(pathname); - // Check if the path is missing the locale + // Handle locale routing first const pathnameIsMissingLocale = i18n.locales.every( (locale) => !pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}` ); - if (pathnameIsMissingLocale) { - // Get the locale (from cookie or fallback to browser preferences) - const locale = getLocale(request) || i18n.defaultLocale; + // Authentication checks (after locale extraction, before locale routing) + // If accessing a protected route without authentication, redirect to login + if (isProtected && !authenticated) { + const loginUrl = new URL(`/${locale}/login`, request.url); + loginUrl.searchParams.set('redirect', pathname); + return NextResponse.redirect(loginUrl); + } + + // If authenticated user tries to access auth pages (login, signup), redirect to home + if (authenticated && isPublic) { + const homeUrl = new URL(`/${locale}`, request.url); + return NextResponse.redirect(homeUrl); + } + // Handle locale prefixing + if (pathnameIsMissingLocale) { // For default locale, rewrite internally (don't redirect) if (locale === i18n.defaultLocale) { const newUrl = request.nextUrl.clone(); @@ -77,9 +162,13 @@ export function middleware(request: NextRequest) { return response; } - // If path has a locale, just continue + // If path has a locale, continue const response = NextResponse.next(); response.headers.set('x-pathname', pathname); + + // Add authentication status to headers for server components + response.headers.set('x-authenticated', authenticated ? 'true' : 'false'); + return response; }