diff --git a/middleware.ts b/middleware.ts new file mode 100644 index 0000000..c499d26 --- /dev/null +++ b/middleware.ts @@ -0,0 +1,19 @@ +import { NextRequest, NextResponse } from "next/server"; +import jwt from "jsonwebtoken"; + +const SECRET_KEY = process.env.JWT_SECRET as string; + +export function middleware(req: NextRequest) { + const token = req.cookies.get("token")?.value; + + if (!token) return NextResponse.redirect(new URL("/login", req.url)); + + try { + jwt.verify(token, SECRET_KEY); + return NextResponse.next(); + } catch (error) { + return NextResponse.redirect(new URL("/login", req.url)); + } +} + +export const config = { matcher: ["/dashboard", "/profile"] }; diff --git a/pages/api/auth/me.ts b/pages/api/auth/me.ts new file mode 100644 index 0000000..0084f0a --- /dev/null +++ b/pages/api/auth/me.ts @@ -0,0 +1,27 @@ +import { NextApiRequest, NextApiResponse } from "next"; +import jwt from "jsonwebtoken"; +import { PrismaClient } from "@prisma/client"; + +const prisma = new PrismaClient(); +const SECRET_KEY = process.env.JWT_SECRET as string; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + const authHeader = req.headers.authorization; + + if (!authHeader || !authHeader.startsWith("Bearer ")) { + return res.status(401).json({ message: "Unauthorized" }); + } + + const token = authHeader.split(" ")[1]; // Extract token + + try { + const decoded: any = jwt.verify(token, SECRET_KEY); + const user = await prisma.user.findUnique({ where: { id: decoded.userId } }); + + if (!user) return res.status(401).json({ message: "User not found" }); + + res.json({ user }); + } catch (error) { + res.status(401).json({ message: "Invalid token" }); + } +} diff --git a/pages/api/login.ts b/pages/api/login.ts new file mode 100644 index 0000000..dda9377 --- /dev/null +++ b/pages/api/login.ts @@ -0,0 +1,24 @@ +import { NextApiRequest, NextApiResponse } from "next"; +import { PrismaClient } from "@prisma/client"; +import bcrypt from "bcrypt"; +import jwt from "jsonwebtoken"; + +const prisma = new PrismaClient(); +const SECRET_KEY = process.env.JWT_SECRET as string; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + if (req.method !== "POST") return res.status(405).json({ message: "Method not allowed" }); + + const { email, password } = req.body; + + const user = await prisma.user.findUnique({ where: { email } }); + if (!user) return res.status(401).json({ message: "Invalid credentials" }); + + const isMatch = await bcrypt.compare(password, user.password); + if (!isMatch) return res.status(401).json({ message: "Invalid credentials" }); + + const token = jwt.sign({ userId: user.id, email: user.email }, SECRET_KEY, { expiresIn: "1h" }); + + res.setHeader("Set-Cookie", `token=${token}; HttpOnly; Path=/; Secure`); + res.json({ token }); +} diff --git a/pages/api/register.ts b/pages/api/register.ts new file mode 100644 index 0000000..5e1e976 --- /dev/null +++ b/pages/api/register.ts @@ -0,0 +1,21 @@ +import { NextApiRequest, NextApiResponse } from "next"; +import { PrismaClient } from "@prisma/client"; +import bcrypt from "bcrypt"; + +const prisma = new PrismaClient(); + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + if (req.method !== "POST") return res.status(405).json({ message: "Method not allowed" }); + + const { email, password } = req.body; + + const existingUser = await prisma.user.findUnique({ where: { email } }); + if (existingUser) return res.status(400).json({ message: "User already exists" }); + + const hashedPassword = await bcrypt.hash(password, 10); + const user = await prisma.user.create({ + data: { email, password: hashedPassword }, + }); + + res.status(201).json({ message: "User registered", user }); +}