No LLM could debug this so I figured I'd put the answer out here: I found that the issue was a bad interaction with the next-intl and supabase auth middleware.
import { updateSession } from '@/utils/supabase/middleware';
import createMiddleware from 'next-intl/middleware';
const nextIntlMiddleware = createMiddleware(routing);
export async function middleware(request: NextRequest) {
...
const intlResponse = nextIntlMiddleware(request);
return await updateSession(request, intlResponse);
}
The tutorial for setting up ssr for supabase auth recommends you use NextResponse.next() when setting the new cookies but this wipes away the state from next-intl middleware which uses rewrites etc etc.
Instead I changed the implamention to reuse the NextReponse created by next-intl and update the cookies there:
export async function updateSession(
request: NextRequest,
supabaseResponse: NextResponse
) {
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, options }) =>
request.cookies.set(name, value)
);
// In the official docs, they say to create a new response object,
// however we already have a response object from the intl middleware.
// These two interact badly with each other because thi NextResponse.next()
// wipes away all the response rewrites the intl middleware does and then
// causes weird routing errors.
// supabaseResponse = NextResponse.next({
// request
// });
cookiesToSet.forEach(({ name, value, options }) =>
supabaseResponse.cookies.set(name, value, options)
);
}
}
}
);
The docs I'm basing this off of is: https://supabase.com/docs/guides/auth/server-side/nextjs