fix(admin): fresh SSR reads, atomic user delete + sanitized errors, cookie-rotation in middleware, no-store on admin APIs
This commit is contained in:
+16
-4
@@ -31,23 +31,35 @@ export async function middleware(request: NextRequest) {
|
||||
// per-route requireAdmin()/requireAdminApi() checks.
|
||||
const path = request.nextUrl.pathname;
|
||||
if (path.startsWith('/admin') || path.startsWith('/api/admin')) {
|
||||
// Carry any cookies Supabase rotated onto the working `response` over to a
|
||||
// deny/redirect response, so a refreshed session/refresh token is always
|
||||
// persisted — otherwise a fresh NextResponse would drop them and a
|
||||
// concurrent request could spuriously 401.
|
||||
const withCookies = (res: NextResponse): NextResponse => {
|
||||
response.cookies.getAll().forEach((cookie) => res.cookies.set(cookie));
|
||||
return res;
|
||||
};
|
||||
if (!user) {
|
||||
if (path.startsWith('/api/admin')) {
|
||||
return NextResponse.json({ error: 'unauthorized' }, { status: 401 });
|
||||
return withCookies(
|
||||
NextResponse.json({ error: 'unauthorized' }, { status: 401 }),
|
||||
);
|
||||
}
|
||||
const url = request.nextUrl.clone();
|
||||
url.pathname = '/login';
|
||||
url.search = '';
|
||||
return NextResponse.redirect(url);
|
||||
return withCookies(NextResponse.redirect(url));
|
||||
}
|
||||
if (user.app_metadata?.role !== 'admin') {
|
||||
if (path.startsWith('/api/admin')) {
|
||||
return NextResponse.json({ error: 'forbidden' }, { status: 403 });
|
||||
return withCookies(
|
||||
NextResponse.json({ error: 'forbidden' }, { status: 403 }),
|
||||
);
|
||||
}
|
||||
const url = request.nextUrl.clone();
|
||||
url.pathname = '/dashboard';
|
||||
url.search = '';
|
||||
return NextResponse.redirect(url);
|
||||
return withCookies(NextResponse.redirect(url));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user