Skip to content

Commit 3aff81c

Browse files
committed
server side role storage added, middleware protection implemented, dashboard layout updated to use server side session checking
1 parent 43f3d04 commit 3aff81c

6 files changed

Lines changed: 113 additions & 73 deletions

File tree

app/(dashboard)/layout.tsx

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,12 @@
1-
import { useSession } from "next-auth/react";
2-
import { getServerSession } from "next-auth/next";
3-
import { redirect } from "next/navigation";
4-
import toast from "react-hot-toast";
1+
import { requireAdmin } from "@/utils/adminAuth";
52

63
export default async function Layout({
74
children,
85
}: Readonly<{
96
children: React.ReactNode;
107
}>) {
11-
const session: {
12-
user: { name: string; email: string; image: string };
13-
} | null = await getServerSession();
14-
15-
if (!session) {
16-
redirect("/");
17-
}
18-
19-
let email: string = await session?.user?.email;
20-
21-
const res = await fetch(`http://localhost:3001/api/users/email/${email}`);
22-
const data = await res.json();
23-
// redirecting user to the home page if not admin
24-
if (data.role === "user") {
25-
redirect("/");
26-
}
8+
// This function handles all authentication and authorization server-side
9+
await requireAdmin();
2710

2811
return <>{children}</>;
2912
}

app/api/auth/[...nextauth]/route.ts

Lines changed: 23 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ export const authOptions: any = {
1818
password: { label: "Password", type: "password" },
1919
},
2020
async authorize(credentials: any) {
21-
2221
try {
2322
const user = await prisma.user.findFirst({
2423
where: {
@@ -31,73 +30,44 @@ export const authOptions: any = {
3130
user.password!
3231
);
3332
if (isPasswordCorrect) {
34-
return user;
33+
return {
34+
id: user.id,
35+
email: user.email,
36+
role: user.role,
37+
};
3538
}
3639
}
3740
} catch (err: any) {
3841
throw new Error(err);
3942
}
4043
},
4144
})
42-
// GithubProvider({
43-
// clientId: process.env.GITHUB_ID ?? "",
44-
// clientSecret: process.env.GITHUB_SECRET ?? "",
45-
// }),
46-
// GoogleProvider({
47-
// clientId: process.env.GOOGLE_ID ?? "",
48-
// clientSecret: process.env.GOOGLE_SECRET ?? "",
49-
// }),
50-
// ...add more providers here if you want. You can find them on nextauth website.
45+
// ... existing providers ...
5146
],
5247
callbacks: {
5348
async signIn({ user, account }: { user: AuthUser; account: Account }) {
5449
if (account?.provider == "credentials") {
5550
return true;
5651
}
57-
// if (account?.provider == "github") {
58-
59-
// try {
60-
// const existingUser = await prisma.user.findFirst({ where: {email: user.email!} });
61-
// if (!existingUser) {
62-
63-
// await prisma.user.create({
64-
// data: {
65-
// id: nanoid() + "",
66-
// email: user.email!
67-
// },
68-
// });
69-
// return true;
70-
// }
71-
// return true;
72-
// } catch (err) {
73-
// console.log("Error saving user", err);
74-
// return false;
75-
// }
76-
// }
77-
78-
// if (account?.provider == "google") {
79-
80-
// try {
81-
// const existingUser = await prisma.user.findFirst({where: { email: user.email! }});
82-
// if (!existingUser) {
83-
// await prisma.user.create({
84-
// data: {
85-
// id: nanoid() + "",
86-
// email: user.email!
87-
// },
88-
// });
89-
90-
// return true;
91-
// }
92-
// return true;
93-
// } catch (err) {
94-
// console.log("Error saving user", err);
95-
// return false;
96-
// }
97-
// }
52+
// ... existing provider logic ...
9853
},
54+
async jwt({ token, user }) {
55+
if (user) {
56+
token.role = user.role;
57+
}
58+
return token;
59+
},
60+
async session({ session, token }) {
61+
if (token) {
62+
session.user.role = token.role;
63+
}
64+
return session;
65+
},
66+
},
67+
pages: {
68+
signIn: '/login',
9969
},
10070
};
10171

10272
export const handler = NextAuth(authOptions);
103-
export { handler as GET, handler as POST };
73+
export { handler as GET, handler as POST };

middleware.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { withAuth } from "next-auth/middleware";
2+
import { NextResponse } from "next/server";
3+
4+
export default withAuth(
5+
function middleware(req) {
6+
// Additional server-side check for admin routes
7+
if (req.nextUrl.pathname.startsWith("/admin")) {
8+
if (req.nextauth.token?.role !== "admin") {
9+
return NextResponse.redirect(new URL("/", req.url));
10+
}
11+
}
12+
},
13+
{
14+
callbacks: {
15+
authorized: ({ token, req }) => {
16+
// Allow access to admin routes only if user is authenticated and has admin role
17+
if (req.nextUrl.pathname.startsWith("/admin")) {
18+
return !!token && token.role === "admin";
19+
}
20+
return true;
21+
},
22+
},
23+
}
24+
);
25+
26+
export const config = {
27+
matcher: ["/admin/:path*"]
28+
};

typings.d.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,26 @@ interface WishListItem {
8080
userId: string;
8181
productId: string;
8282
product: Product;
83+
}
84+
85+
86+
declare module "next-auth" {
87+
interface Session {
88+
user: {
89+
name: string;
90+
email: string;
91+
image: string;
92+
role: string;
93+
};
94+
}
95+
96+
interface User {
97+
role: string;
98+
}
99+
}
100+
101+
declare module "next-auth/jwt" {
102+
interface JWT {
103+
role: string;
104+
}
83105
}

utils/adminAuth.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { getServerSession } from "next-auth/next";
2+
import { authOptions } from "@/app/api/auth/[...nextauth]/route";
3+
import { redirect } from "next/navigation";
4+
5+
export async function requireAdmin() {
6+
const session = await getServerSession(authOptions);
7+
8+
if (!session) {
9+
redirect("/login");
10+
}
11+
12+
if ((session as any)?.user?.role !== "admin") {
13+
redirect("/");
14+
}
15+
16+
return session;
17+
}
18+
19+
export async function isAdmin(): Promise<boolean> {
20+
const session = await getServerSession(authOptions);
21+
return (session as any)?.user?.role === "admin";
22+
}
23+

utils/auth.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { getServerSession } from "next-auth/next";
2+
import { authOptions } from "@/app/api/auth/[...nextauth]/route";
3+
4+
export async function isAdmin(): Promise<boolean> {
5+
const session = await getServerSession(authOptions);
6+
return (session as any)?.user?.role === "admin";
7+
}
8+
9+
export async function requireAdmin() {
10+
const admin = await isAdmin();
11+
if (!admin) {
12+
throw new Error("Admin access required");
13+
}
14+
}

0 commit comments

Comments
 (0)