Folks, I have spent days trying to figure out the error: POST /auth/v1/token?grant_type=refresh_token HTTP/1.1" 400 93 "-" "Next.js Middleware
Basically, I have a nextjs web app that uses supabase as its backend, its hosted on Hostinger VPS, I have the webserver, the webapp and supabase hosted on docker.
The thing is, everything works super smooth when my nextjs app docker container is restarted, but after 1-2ish days or hours, not sure what is the reason, application gets very slow, and i check the docker stats to find the app using over 100% CPU and in the nginx access log, all i see is: POST /auth/v1/token?grant_type=refresh_token HTTP/1.1" 400 93 "-" "Next.js Middleware, rapidly uncontrollably this keeps on happening, which is leading to the CPU usage and hence the slowdown of the app.
My Middleware:
import { createMiddlewareClient } from "@supabase/auth-helpers-nextjs";
import { NextResponse } from "next/server";
export async function middleware(req) {
const res = NextResponse.next();
// Add security headers
res.headers.set("X-Content-Type-Options", "nosniff");
res.headers.set("X-Frame-Options", "DENY");
res.headers.set("X-XSS-Protection", "1; mode=block");
res.headers.set("Referrer-Policy", "strict-origin-when-cross-origin");
res.headers.set(
"Permissions-Policy",
"camera=(), microphone=(), geolocation=()"
);
// Add this to your existing security headers
res.headers.set(
"Content-Security-Policy",
`default-src 'self';
script-src 'self' 'unsafe-eval' 'unsafe-inline';
style-src 'self' 'unsafe-inline';
img-src 'self' data: blob: https: http://localhost:8000;
font-src 'self' data:;
connect-src 'self' https: http://localhost:8000 ws://localhost:8000 wss://app.domain;
media-src 'self' https:;
object-src 'none';
frame-src 'self' ;
frame-ancestors 'self';
worker-src 'self' blob:;`
.replace(/\s+/g, " ")
.trim()
);
const supabase = createMiddlewareClient({ req, res });
try {
const {
data: { user },
error,
} = await supabase.auth.getUser();
// Define route types
const publicRoutes = [
"/sign-in",
"/reset-password",
"/update-password",
"/sign-up",
"/unauthorized",
"/api/public",
"/api/test-email", // Add any public API endpoints here
];
// const privPublicRoutes = ["/reset-password", "/update-password"];
const adminRoutes = ["/admin", "/dashboard/admin"];
const isAdminApiRoute = req.nextUrl.pathname.startsWith("/api/admin");
// Static file handling
const isStaticFile =
req.nextUrl.pathname.startsWith("/_next") ||
req.nextUrl.pathname.startsWith("/static") ||
req.nextUrl.pathname.includes(".");
if (isStaticFile) {
return res;
}
// Route checks
const isPublicRoute = publicRoutes.some((route) =>
req.nextUrl.pathname.startsWith(route)
);
const isAdminRoute = adminRoutes.some((route) =>
req.nextUrl.pathname.startsWith(route)
);
const isApiRoute = req.nextUrl.pathname.startsWith("/api");
// Authentication check
const isAuthenticated = !error && user;
const isAdmin = user?.user_metadata?.role === "admin";
// API Route handling
if (isApiRoute) {
// Handle admin API routes
if (isAdminApiRoute) {
if (!isAuthenticated || !isAdmin) {
return NextResponse.json(
{ error: "Forbidden: Admin access required" },
{ status: 403 }
);
}
addUserHeaders(res, user, true);
return res;
}
// Handle public API routes
if (isPublicRoute) {
return res;
}
// All other API routes require authentication
if (!isAuthenticated) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
addUserHeaders(res, user, false);
return res;
}
// Page Route handling
if (isAuthenticated) {
// Redirect authenticated users away from public routes
if (isPublicRoute) {
return NextResponse.redirect(new URL("/", req.url));
}
// Check admin access for admin routes
if (isAdminRoute && !isAdmin) {
return NextResponse.redirect(new URL("/unauthorized", req.url));
}
addUserHeaders(res, user, isAdmin);
return res;
}
// Handle unauthenticated users
if (!isPublicRoute) {
const redirectUrl = new URL("/sign-in", req.url);
redirectUrl.searchParams.set("returnUrl", req.nextUrl.pathname);
return NextResponse.redirect(redirectUrl);
}
return res;
} catch (error) {
console.error("Middleware Error:", error);
if (req.nextUrl.pathname.startsWith("/api")) {
return NextResponse.json(
{ error: "Authentication error" },
{ status: 401 }
);
}
// Only redirect to sign-in if not on a public route
if (!publicRoutes.some((route) => req.nextUrl.pathname.startsWith(route))) {
const redirectUrl = new URL("/sign-in", req.url);
redirectUrl.searchParams.set("returnUrl", req.nextUrl.pathname);
return NextResponse.redirect(redirectUrl);
}
return res;
}
}
// Helper function to add user headers
function addUserHeaders(res, user, isAdmin) {
// Sanitize and add user data to headers
res.headers.set("x-user-id", user.id);
res.headers.set("x-user-email", user.email);
res.headers.set("x-user-role", isAdmin ? "admin" : "user");
res.headers.set("x-user-name", user.user_metadata?.full_name || "");
}
export const config = {
matcher: [
/*
* Match all request paths except:
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico (favicon file)
* - public folder
* - public files with extensions (.svg, .jpg, etc)
*/
"/((?!_next/static|_next/image|favicon.ico|public/|.*\\.[\\w]+$).*)",
],
};
Please please help someone!