diff --git a/middleware.ts b/middleware.ts new file mode 100644 index 0000000..1b4214b --- /dev/null +++ b/middleware.ts @@ -0,0 +1,49 @@ +import { type NextRequest, NextResponse } from 'next/server' +import { updateSession } from '@/lib/supabase/middleware' + +// Routes that require authentication +const protectedRoutes = ['/dashboard', '/settings', '/subscription'] + +// Routes that should redirect to dashboard if already authenticated +const authRoutes = ['/login', '/register'] + +export async function middleware(request: NextRequest) { + const { supabaseResponse, user } = await updateSession(request) + const { pathname } = request.nextUrl + + // Check if trying to access protected route without auth + const isProtectedRoute = protectedRoutes.some(route => + pathname.startsWith(route) + ) + + if (isProtectedRoute && !user) { + const redirectUrl = new URL('/login', request.url) + // Save the original URL to redirect back after login + redirectUrl.searchParams.set('redirectTo', pathname) + return NextResponse.redirect(redirectUrl) + } + + // Check if trying to access auth routes while already authenticated + const isAuthRoute = authRoutes.some(route => + pathname.startsWith(route) + ) + + if (isAuthRoute && user) { + return NextResponse.redirect(new URL('/dashboard', request.url)) + } + + return supabaseResponse +} + +export const config = { + matcher: [ + /* + * Match all request paths except for the ones starting with: + * - _next/static (static files) + * - _next/image (image optimization files) + * - favicon.ico (favicon file) + * - public folder files + */ + '/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)', + ], +} diff --git a/src/lib/supabase/middleware.ts b/src/lib/supabase/middleware.ts new file mode 100644 index 0000000..9b80647 --- /dev/null +++ b/src/lib/supabase/middleware.ts @@ -0,0 +1,37 @@ +import { createServerClient } from '@supabase/ssr' +import { NextResponse, type NextRequest } from 'next/server' + +export async function updateSession(request: NextRequest) { + let supabaseResponse = NextResponse.next({ + request, + }) + + const supabase = createServerClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, + { + cookies: { + getAll() { + return request.cookies.getAll() + }, + setAll(cookiesToSet) { + cookiesToSet.forEach(({ name, value }) => + request.cookies.set(name, value) + ) + supabaseResponse = NextResponse.next({ + request, + }) + cookiesToSet.forEach(({ name, value, options }) => + supabaseResponse.cookies.set(name, value, options) + ) + }, + }, + } + ) + + // IMPORTANT: Do not remove this line + // Refreshing the auth token is crucial for keeping the session alive + const { data: { user } } = await supabase.auth.getUser() + + return { supabaseResponse, user } +}