Skip to content

Commit 7577556

Browse files
committed
feat: add secure middleware for protect dashboard and update tokens
1 parent 8eca67e commit 7577556

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { NextResponse, type NextRequest } from "next/server";
2+
import { updateSession } from "./supabase/middleware";
3+
import { type JwtPayload, jwtDecode } from "jwt-decode";
4+
import { createClient } from "./supabase/server";
5+
6+
const adminPaths = ["/dashboard"];
7+
const authPaths = ["/register", "/login"];
8+
9+
export async function middleware(request: NextRequest) {
10+
await updateSession(request);
11+
12+
const supabase = createClient();
13+
const {
14+
data: { user },
15+
error,
16+
} = await supabase.auth.getUser();
17+
18+
const url = request.nextUrl.clone();
19+
const pathname = url.pathname;
20+
const nextPath = url.searchParams.get("next");
21+
22+
if (adminPaths.includes(pathname)) {
23+
if (!user || error) {
24+
url.pathname = "/login";
25+
url.searchParams.set("next", nextPath ?? pathname);
26+
27+
return NextResponse.redirect(url);
28+
}
29+
30+
// * Check if user is admin
31+
supabase.auth.onAuthStateChange(async (_, session) => {
32+
if (session) {
33+
const jwt = jwtDecode(session.access_token) as JwtPayload & {
34+
user_role: string;
35+
};
36+
const userRole = jwt.user_role as string | null;
37+
const isAdmin = userRole === "admin";
38+
39+
if (!isAdmin) {
40+
url.pathname = "/unauthorized";
41+
NextResponse.redirect(url);
42+
return;
43+
}
44+
45+
NextResponse.next();
46+
return;
47+
}
48+
url.pathname = "/login";
49+
url.searchParams.set("next", nextPath ?? pathname);
50+
NextResponse.redirect(url);
51+
return;
52+
});
53+
}
54+
55+
if (authPaths.includes(pathname)) {
56+
if (user != null || !error) {
57+
url.pathname = "/";
58+
return NextResponse.redirect(url);
59+
}
60+
return NextResponse.next();
61+
}
62+
63+
return NextResponse.next();
64+
}
65+
66+
export const config = {
67+
matcher: [
68+
"/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",
69+
"/dashboard/:path*",
70+
],
71+
};

0 commit comments

Comments
 (0)