+ Espace hôte
+
+ Accès autorisé pour {session.user.email} ({session.user.role}).
+
+
+
+
+ Gérer mes carbets
+
+
+
+ );
+}
diff --git a/src/auth.ts b/src/auth.ts
new file mode 100644
index 0000000..4071c3d
--- /dev/null
+++ b/src/auth.ts
@@ -0,0 +1,75 @@
+import NextAuth from "next-auth";
+import Credentials from "next-auth/providers/credentials";
+
+import { prisma } from "@/lib/prisma";
+import { verifyPassword } from "@/lib/password";
+
+export const { handlers, auth, signIn, signOut } = NextAuth({
+ session: {
+ strategy: "jwt",
+ },
+ providers: [
+ Credentials({
+ name: "Email et mot de passe",
+ credentials: {
+ email: { label: "Email", type: "email" },
+ password: { label: "Mot de passe", type: "password" },
+ },
+ async authorize(credentials) {
+ const email = credentials?.email?.toString().trim().toLowerCase();
+ const password = credentials?.password?.toString() ?? "";
+
+ if (!email || !password) {
+ return null;
+ }
+
+ const user = await prisma.user.findUnique({
+ where: { email },
+ select: {
+ id: true,
+ email: true,
+ firstName: true,
+ lastName: true,
+ role: true,
+ isActive: true,
+ passwordHash: true,
+ },
+ });
+
+ if (!user || !user.isActive) {
+ return null;
+ }
+
+ const isValid = await verifyPassword(password, user.passwordHash);
+ if (!isValid) {
+ return null;
+ }
+
+ return {
+ id: user.id,
+ email: user.email,
+ name: `${user.firstName} ${user.lastName}`.trim(),
+ role: user.role,
+ };
+ },
+ }),
+ ],
+ callbacks: {
+ async jwt({ token, user }) {
+ if (user?.role) {
+ token.role = user.role;
+ }
+ return token;
+ },
+ async session({ session, token }) {
+ if (session.user) {
+ session.user.id = token.sub ?? "";
+ session.user.role = token.role;
+ }
+ return session;
+ },
+ },
+ pages: {
+ signIn: "/connexion",
+ },
+});
diff --git a/src/lib/authorization.ts b/src/lib/authorization.ts
new file mode 100644
index 0000000..4841b1d
--- /dev/null
+++ b/src/lib/authorization.ts
@@ -0,0 +1,23 @@
+import { redirect } from "next/navigation";
+
+import { auth } from "@/auth";
+import type { UserRole } from "@/generated/prisma/enums";
+
+export async function requireAuth() {
+ const session = await auth();
+ if (!session?.user?.id) {
+ redirect("/connexion");
+ }
+
+ return session;
+}
+
+export async function requireRole(allowedRoles: UserRole[]) {
+ const session = await requireAuth();
+
+ if (!session.user.role || !allowedRoles.includes(session.user.role)) {
+ redirect("/");
+ }
+
+ return session;
+}
diff --git a/src/lib/password.ts b/src/lib/password.ts
new file mode 100644
index 0000000..78d7cb4
--- /dev/null
+++ b/src/lib/password.ts
@@ -0,0 +1,12 @@
+import bcrypt from "bcryptjs";
+
+export async function verifyPassword(
+ plainTextPassword: string,
+ hashedPassword: string,
+): Promise