A secure /admin route built with HTTP Basic Auth, Supabase service_role, and zero extra dependencies.
Every data-driven portfolio eventually needs a way to monitor its own data without opening the Supabase dashboard every time. I wanted to see my contact messages, project counts, and certification state at a glance — but building a full auth system felt like massive overkill for a personal tool.
The challenge: how do you protect an internal route in Next.js 16 with zero new dependencies, while still being able to read tables that are locked behind Row Level Security for anonymous users?
function adminAuth(request: NextRequest): NextResponse | null {
const expectedUser = process.env.ADMIN_USERNAME;
const expectedPass = process.env.ADMIN_PASSWORD;
if (!expectedUser || !expectedPass) {
return new NextResponse("Admin not configured.", { status: 503 });
}
const authHeader = request.headers.get("authorization");
if (authHeader?.startsWith("Basic ")) {
try {
const decoded = atob(authHeader.slice(6)); // Edge-safe — no Buffer
const colonIdx = decoded.indexOf(":");
if (colonIdx !== -1) {
const user = decoded.slice(0, colonIdx);
const pass = decoded.slice(colonIdx + 1);
if (user === expectedUser && pass === expectedPass) {
return null; // ✅ authorized
}
}
} catch {
// malformed base64 — reject
}
}
return new NextResponse("Authentication required.", {
status: 401,
headers: { "WWW-Authenticate": 'Basic realm="Admin", charset="UTF-8"' },
});
}