diff --git a/app/components/Login.jsx b/app/components/Login.jsx index ca70213..18be251 100644 --- a/app/components/Login.jsx +++ b/app/components/Login.jsx @@ -39,8 +39,11 @@ export const Login = () => { const data = await response.json(); if (!data.success) return setErrMsg(data.msg); - - localStorage.setItem("token", data.token); + if (data.token) { + document.cookie = `token=${ + data.token + };SameSite=None; Secure; path=/; max-age=${3600 * 24 * 31}; `; + } router.push("/dashboard"); } catch (err) { console.log(err); diff --git a/app/components/Register.jsx b/app/components/Register.jsx index 4d69cd5..be7a802 100644 --- a/app/components/Register.jsx +++ b/app/components/Register.jsx @@ -41,7 +41,12 @@ export const Register = () => { const data = await response.json(); if (!data.success) return setErrMsg(data.msg); - + if (data.token) { + document.cookie = `token=${ + data.token + };SameSite=None; Secure; path=/; max-age=${3600 * 24 * 31}; `; + } + console.log(data); router.push("/dashboard"); } catch (err) { console.log(err); diff --git a/middleware.js b/middleware.js new file mode 100644 index 0000000..a5ee6ad --- /dev/null +++ b/middleware.js @@ -0,0 +1,27 @@ +import { NextResponse } from "next/server"; +import { jwtVerify } from "jose"; +// This function can be marked `async` if using `await` inside +export async function middleware(request) { + const token = request.cookies.get("token"); + if (token) { + try { + const secret = new TextEncoder().encode(process.env.JWT_SECRET); + console.log("secret", secret); + + // Verify the token using jose in Edge Middleware + const { payload } = await jwtVerify(token.value, secret); + console.log("payload", payload); + if (payload) { + return NextResponse.next(); + } + } catch (error) { + console.error("Token verification failed:", error); + } + } + return NextResponse.redirect(new URL("/", request.url)); +} + +// See "Matching Paths" below to learn more +export const config = { + matcher: "/dashboard", +}; diff --git a/package-lock.json b/package-lock.json index 6f8cdf7..1ef7cd6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "0.1.0", "dependencies": { "bcrypt": "^5.1.1", + "jose": "^5.9.6", "jsonwebtoken": "^9.0.2", "mongodb": "^6.9.0", "next": "14.2.13", @@ -3391,6 +3392,15 @@ "jiti": "bin/jiti.js" } }, + "node_modules/jose": { + "version": "5.9.6", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.9.6.tgz", + "integrity": "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", diff --git a/package.json b/package.json index 6d2eaf1..50bc175 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ }, "dependencies": { "bcrypt": "^5.1.1", + "jose": "^5.9.6", "jsonwebtoken": "^9.0.2", "mongodb": "^6.9.0", "next": "14.2.13", diff --git a/pages/api/add-user.js b/pages/api/add-user.js index 6ac178c..3db9641 100644 --- a/pages/api/add-user.js +++ b/pages/api/add-user.js @@ -1,72 +1,89 @@ -import {addUserModel, getUserModel} from "@/app/models/userModel"; +import { addUserModel, getUserModel } from "@/app/models/userModel"; import bcrypt from "bcrypt"; - +import jwt from "jsonwebtoken"; export default function addUser(req, res) { - - const result = validateRequest(req); - - if(!result.success){ - return res.json(result); - } - - handleRequest({req, res}); -}; + const result = validateRequest(req); + if (!result.success) { + return res.json(result); + } -async function handleRequest(param){ - const {req, res} = param; + handleRequest({ req, res }); +} - //check if user exists already - try{ - const query = { - $or: [ - {username: req.body.username}, - {emailAddress: req.body.emailAddress} - ] - }; +async function handleRequest(param) { + const { req, res } = param; - const result = await getUserModel(query); - if(result){ - res.status(400).json({success: false, msg: "Username or e-mail exists already"}); - return; - } - } - catch(err){ - console.log(err); - res.status(500).json({success: false, msg: "Internal server error."}); - return; - } + //check if user exists already + try { + const query = { + $or: [ + { username: req.body.username }, + { emailAddress: req.body.emailAddress }, + ], + }; - //add user to db - try{ - const hashedPassword = await bcrypt.hash(req.body.password, 10); - const doc = { - username: req.body.username, - emailAddress: req.body.emailAddress, - password: hashedPassword - }; + const result = await getUserModel(query); + if (result) { + res + .status(400) + .json({ success: false, msg: "Username or e-mail exists already" }); + return; + } + } catch (err) { + console.log(err); + res.status(500).json({ success: false, msg: "Internal server error." }); + return; + } - const result = await addUserModel(doc); - } - catch(err){ - console.log(err); - res.status(500).json({success: false, msg: "Internal server error."}); - return; - } + //add user to db + try { + const hashedPassword = await bcrypt.hash(req.body.password, 10); + const doc = { + username: req.body.username, + emailAddress: req.body.emailAddress, + password: hashedPassword, + }; - res.status(200).json({success: true, msg: "User has been added to db."}); + const result = await addUserModel(doc); + let token = null; + try { + token = jwt.sign( + { + _id: result.insertedId, + username: req.body.username, + emailAddress: req.body.emailAddress, + password: hashedPassword, + }, + process.env.JWT_SECRET + ); + } catch (err) { + console.log(err); + return res.status(200).json({ + success: true, + msg: "User added to db but failed to create token.", + token, + }); + } + return res + .status(200) + .json({ success: true, msg: "User has been added to db.", token }); + } catch (err) { + console.log(err); + res.status(500).json({ success: false, msg: "Internal server error." }); + return; + } } +function validateRequest(req) { + if (req.method !== "POST") { + return { success: false, msg: "Only POST requests are allowed" }; + } -function validateRequest(req){ - if(req.method !== "POST"){ - return {success: false, msg: "Only POST requests are allowed"}; - } - - if(!req.body.username || !req.body.emailAddress || !req.body.password){ - return {success: false, msg: "Not all credentials have been provided."}; - } + if (!req.body.username || !req.body.emailAddress || !req.body.password) { + return { success: false, msg: "Not all credentials have been provided." }; + } - return {success: true}; + return { success: true }; } diff --git a/pages/api/sign-in.js b/pages/api/sign-in.js index 64f1544..c7e6124 100644 --- a/pages/api/sign-in.js +++ b/pages/api/sign-in.js @@ -1,51 +1,65 @@ import jwt from "jsonwebtoken"; import bcrypt from "bcrypt"; -import {getUserModel} from "@/app/models/userModel"; +import { getUserModel } from "@/app/models/userModel"; -export default function signIn(req, res){ - - handleRequest({req, res}); +export default function signIn(req, res) { + handleRequest({ req, res }); } +async function handleRequest(param) { + const { req, res } = param; -async function handleRequest(param){ - const {req, res} = param; - - //get user - let user = null; - try{ - const query = { - $or: [ - {username: req.body.nameOrEmail}, - {emailAddress: req.body.nameOrEmail}, - ], - } + //get user + let user = null; + try { + const query = { + $or: [ + { username: req.body.nameOrEmail }, + { emailAddress: req.body.nameOrEmail }, + ], + }; - user = await getUserModel(query); - if(!user){ - return res.status(400).json({success: false, msg: "No user has been found:"}); - } + user = await getUserModel(query); + console.log(user); + if (!user) { + return res + .status(400) + .json({ success: false, msg: "No user has been found:" }); + } - const isCorrectPwd = await bcrypt.compare(req.body.password, user.password); - if(!isCorrectPwd){ - return res.status(400).json({success: false, msg: "Wrong password."}); - } - } - catch(err){ - console.log(err); - return res.status(500).json({success: false, msg: "Internal server error."}); - } + const isCorrectPwd = await bcrypt.compare(req.body.password, user.password); + if (!isCorrectPwd) { + return res.status(400).json({ success: false, msg: "Wrong password." }); + } + } catch (err) { + console.log(err); + return res + .status(500) + .json({ success: false, msg: "Internal server error." }); + } - //create token - let token = null; - try{ - token = await jwt.sign(user, process.env.JWT_SECRET); - } - catch(err){ - console.log(err); - return res.status(500).json({success: false, msg: "Internal server error."}); - } + //create token + let token = null; + console.log(user._id); + try { + token = jwt.sign( + { + _id: user._id, + username: user.username, + emailAddress: user.emailAddress, + password: user.password, + }, + process.env.JWT_SECRET + ); + } catch (err) { + console.log(err); + return res + .status(500) + .json({ success: false, msg: "Internal server error." }); + } - res.setHeader("Authorization", `Bearer ${token}`); - res.status(200).json({success: true, msg: "Authorization header set.", token}); + res.setHeader("Authorization", `Bearer ${token}`); + res + .status(200) + .json({ success: true, msg: "Authorization header set.", token }); }