From ca51db2887f1534e658df8b12b4347482ce226d6 Mon Sep 17 00:00:00 2001 From: Samarth Vaidya Date: Tue, 15 Oct 2024 16:57:03 +0530 Subject: [PATCH 01/17] save local changes --- backend/config/passport.config.js | 33 +++++++++++++++++++++++ backend/controller/customer.controller.js | 7 ++++- backend/index.js | 6 ++++- backend/package.json | 2 ++ backend/routes/customerRouter.js | 27 +++++++++++-------- 5 files changed, 62 insertions(+), 13 deletions(-) create mode 100644 backend/config/passport.config.js diff --git a/backend/config/passport.config.js b/backend/config/passport.config.js new file mode 100644 index 00000000..dddb724e --- /dev/null +++ b/backend/config/passport.config.js @@ -0,0 +1,33 @@ +// passportConfig.js +const { Strategy: JwtStrategy, ExtractJwt } = require("passport-jwt"); +const passport = require("passport"); +const config = require("./secret"); +const Customer = require("../models/customer.model"); + +// Secret key to sign the JWT token +const secret = config.JWT_SECRET; +console.log(secret); +const opts = { + jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), + secretOrKey: "secret", +}; + +passport.use( + new JwtStrategy(opts, (jwt_payload, done) => { + // jwt_payload contains the decoded token + // You can use the payload data (such as user id) to check if the user exists + const userId = jwt_payload.sub; + Customer.findById(userId) + .then((user) => { + if (user) { + return done(null, user); + } + return done(null, false); + }) + .catch((error) => { + return done(error, false); + }); + }) +); + +module.exports = passport; diff --git a/backend/controller/customer.controller.js b/backend/controller/customer.controller.js index be6d30dd..d8de6853 100644 --- a/backend/controller/customer.controller.js +++ b/backend/controller/customer.controller.js @@ -61,8 +61,13 @@ async function loginCustomer(req, res) { if (!validPassword) { return res.status(401).json({ error: "Invalid email or password" }); } + const payload = { + sub: customer._id, // User ID + name: customer.name, // Optional + email: customer.email, // Optional + }; const token = jwt.sign( - { id: customer._id }, + payload, process.env.JWT_SECRET, { expiresIn: "1h" }, // Expires in 1 hour ); diff --git a/backend/index.js b/backend/index.js index 135682a0..7092f588 100644 --- a/backend/index.js +++ b/backend/index.js @@ -4,6 +4,7 @@ const mongoose = require("mongoose"); const dotenv = require("dotenv"); const logger = require("./config/logger"); const errorMiddleware = require("./middlewares/errrorMiddleware"); +const passport = require("passport"); dotenv.config(); const app = express(); @@ -13,7 +14,7 @@ const port = process.env.PORT || 3000; app.use( cors({ origin: ["http://localhost:5173", "https://play-cafe.vercel.app"], - }), + }) ); // CORS configuration @@ -43,6 +44,9 @@ mongoose // Enable CORS preflight for the create reservation route only // app.options("/api/reservation/create", cors(corsOptions)); +// Initialize passport middleware +app.use(passport.initialize()); + // API routes app.use("/api", require("./routes/index")); diff --git a/backend/package.json b/backend/package.json index 739b5cae..f77102a4 100644 --- a/backend/package.json +++ b/backend/package.json @@ -22,6 +22,8 @@ "jsonwebtoken": "^9.0.2", "mongoose": "^8.7.0", "nodemailer": "^6.9.15", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1", "validator": "^13.12.0", "winston": "^3.14.2", "zod": "^3.23.8" diff --git a/backend/routes/customerRouter.js b/backend/routes/customerRouter.js index 0b929a0b..9fd05fb3 100644 --- a/backend/routes/customerRouter.js +++ b/backend/routes/customerRouter.js @@ -5,20 +5,25 @@ const { resetPassword, } = require("../controller/customer.controller"); const authenticateCustomer = require("../middlewares/authCustomer"); +const passport = require("../config/passport.config"); const router = express.Router(); require("dotenv").config(); -router.get("/", authenticateCustomer, (req, res) => { - res.json({ - message: "Welcome to the User API!", - version: "1.0.0", - endpoints: { - login: "/login", - register: "/register", - }, - documentation: "https://api-docs-url.com", - }); -}); +router.get( + "/", + passport.authenticate("jwt", { session: false }), + (req, res) => { + res.json({ + message: "Welcome to the User API!", + version: "1.0.0", + endpoints: { + login: "/login", + register: "/register", + }, + documentation: "https://api-docs-url.com", + }); + } +); router.post("/register", createCustomer); router.post("/login", loginCustomer); From af1c1635d7ecc80ac32fa62d905c1797d7cc5849 Mon Sep 17 00:00:00 2001 From: Samarth Vaidya Date: Tue, 15 Oct 2024 17:13:30 +0530 Subject: [PATCH 02/17] feat(auth): integrate JWT authentication using passport-jwt - Added passport-jwt strategy for authenticating users via JWT tokens - Configured JWT extraction from Authorization header using Bearer scheme - Implemented user verification based on JWT payload (user ID) from the database - Set up a JWT secret key using configuration/environment variables --- backend/config/passport.config.js | 40 ++++++++++++++++------- backend/controller/admin.controller.js | 18 +++++----- backend/controller/customer.controller.js | 15 +++++---- backend/routes/adminRouter.js | 27 ++++++++------- 4 files changed, 63 insertions(+), 37 deletions(-) diff --git a/backend/config/passport.config.js b/backend/config/passport.config.js index dddb724e..0b8ec485 100644 --- a/backend/config/passport.config.js +++ b/backend/config/passport.config.js @@ -3,30 +3,48 @@ const { Strategy: JwtStrategy, ExtractJwt } = require("passport-jwt"); const passport = require("passport"); const config = require("./secret"); const Customer = require("../models/customer.model"); +const Admin = require("../models/admin.model"); // Secret key to sign the JWT token const secret = config.JWT_SECRET; console.log(secret); const opts = { jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), - secretOrKey: "secret", + secretOrKey: secret, }; passport.use( new JwtStrategy(opts, (jwt_payload, done) => { // jwt_payload contains the decoded token // You can use the payload data (such as user id) to check if the user exists + const userId = jwt_payload.sub; - Customer.findById(userId) - .then((user) => { - if (user) { - return done(null, user); - } - return done(null, false); - }) - .catch((error) => { - return done(error, false); - }); + const role = jwt_payload.role; + console.log(role); + if (role == "customer") { + Customer.findById(userId) + .then((user) => { + if (user) { + return done(null, user); + } + return done(null, false); + }) + .catch((error) => { + return done(error, false); + }); + } + if (role == "admin") { + Admin.findById(userId) + .then((user) => { + if (user) { + return done(null, user); + } + return done(null, false); + }) + .catch((error) => { + return done(error, false); + }); + } }) ); diff --git a/backend/controller/admin.controller.js b/backend/controller/admin.controller.js index 0f12a0ae..dbd74083 100644 --- a/backend/controller/admin.controller.js +++ b/backend/controller/admin.controller.js @@ -59,18 +59,20 @@ async function loginAdmin(req, res) { } const validPassword = await bcrypt.compare( req.body.password, - admin.password, + admin.password ); if (!validPassword) { return res.status(401).json({ error: "Invalid email or password" }); } - const token = jwt.sign( - { id: admin._id, role: "admin" }, - process.env.JWT_SECRET, - { - expiresIn: "1h", - }, - ); + const payload = { + sub: admin._id, // User ID + name: admin.name, // Optional + role: "admin", // Optional + email: admin.email, // Optional + }; + const token = jwt.sign(payload, process.env.JWT_SECRET, { + expiresIn: "1h", + }); res.json({ message: "Login successful", token, diff --git a/backend/controller/customer.controller.js b/backend/controller/customer.controller.js index d8de6853..4937e2af 100644 --- a/backend/controller/customer.controller.js +++ b/backend/controller/customer.controller.js @@ -56,20 +56,21 @@ async function loginCustomer(req, res) { } const validPassword = await bcrypt.compare( req.body.password, - customer.password, + customer.password ); if (!validPassword) { return res.status(401).json({ error: "Invalid email or password" }); } - const payload = { - sub: customer._id, // User ID - name: customer.name, // Optional - email: customer.email, // Optional - }; + const payload = { + sub: customer._id, // User ID + name: customer.name, // Optional + role: "customer", // Optional + email: customer.email, // Optional + }; const token = jwt.sign( payload, process.env.JWT_SECRET, - { expiresIn: "1h" }, // Expires in 1 hour + { expiresIn: "1h" } // Expires in 1 hour ); res.json({ message: "Login successful", diff --git a/backend/routes/adminRouter.js b/backend/routes/adminRouter.js index 197f5556..7f9bad13 100644 --- a/backend/routes/adminRouter.js +++ b/backend/routes/adminRouter.js @@ -1,20 +1,25 @@ const express = require("express"); const { createAdmin, loginAdmin } = require("../controller/admin.controller"); const authenticateAdmin = require("../middlewares/authAdmin"); +const passport = require("../config/passport.config"); const router = express.Router(); require("dotenv").config(); -router.get("/", authenticateAdmin, (req, res) => { - res.json({ - message: "Welcome to the Admin API!", - version: "1.0.0", - endpoints: { - login: "/login", - register: "/register", - }, - documentation: "https://api-docs-url.com", - }); -}); +router.get( + "/", + passport.authenticate("jwt", { session: false }), + (req, res) => { + res.json({ + message: "Welcome to the Admin API!", + version: "1.0.0", + endpoints: { + login: "/login", + register: "/register", + }, + documentation: "https://api-docs-url.com", + }); + } +); router.post("/register", createAdmin); router.post("/login", loginAdmin); From 1b09d35bd787e7eeb618f00883d1eabcab9ad0b5 Mon Sep 17 00:00:00 2001 From: Aditya Bakshi Date: Tue, 15 Oct 2024 18:45:56 +0530 Subject: [PATCH 03/17] logn and signup are responsible --- frontend/src/components/Pages/Login.jsx | 10 +++++++--- frontend/src/components/Pages/Signup.jsx | 21 ++++++++++++++------- package-lock.json | 6 ++++++ 3 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 package-lock.json diff --git a/frontend/src/components/Pages/Login.jsx b/frontend/src/components/Pages/Login.jsx index c8b9fd59..795759d7 100644 --- a/frontend/src/components/Pages/Login.jsx +++ b/frontend/src/components/Pages/Login.jsx @@ -61,10 +61,14 @@ const Login = () => { login
handleSubmit(e)} - className="form z-10 p-16 bg-lightblue flex flex-col items-start justify-center gap-5 rounded-lg border-2 border-black shadow-[4px_4px_0px_0px_black] bg-[#f1e9dc]" + className="form z-10 p-16 bg-lightblue flex flex-col items-start justify-center gap-5 rounded-lg border-2 border-black shadow-[4px_4px_0px_0px_black] + md: p-2 + bg-[#f1e9dc]" > -
- Welcome, +
+ Welcome
Log in to continue diff --git a/frontend/src/components/Pages/Signup.jsx b/frontend/src/components/Pages/Signup.jsx index 01170179..09b04259 100644 --- a/frontend/src/components/Pages/Signup.jsx +++ b/frontend/src/components/Pages/Signup.jsx @@ -96,19 +96,26 @@ const Signup = () => { }; return ( -
+
login - -
- Play Cafe, + +
+
+ + Play Cafe, +

- + Register to continue
{ {error}
)} -

+

Already have an account? Login diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..a0c27c60 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "PlayCafe", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} From ea715428919ad10830de4419c0f27f5c33ee5ce4 Mon Sep 17 00:00:00 2001 From: Samarth Vaidya Date: Tue, 15 Oct 2024 19:04:07 +0530 Subject: [PATCH 04/17] coderabbit changes --- backend/config/passport.config.js | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/backend/config/passport.config.js b/backend/config/passport.config.js index 0b8ec485..ec2bf4a1 100644 --- a/backend/config/passport.config.js +++ b/backend/config/passport.config.js @@ -7,7 +7,6 @@ const Admin = require("../models/admin.model"); // Secret key to sign the JWT token const secret = config.JWT_SECRET; -console.log(secret); const opts = { jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), secretOrKey: secret, @@ -20,21 +19,13 @@ passport.use( const userId = jwt_payload.sub; const role = jwt_payload.role; - console.log(role); - if (role == "customer") { - Customer.findById(userId) - .then((user) => { - if (user) { - return done(null, user); - } - return done(null, false); - }) - .catch((error) => { - return done(error, false); - }); - } - if (role == "admin") { - Admin.findById(userId) + const roleModelMap = { + customer: Customer, + admin: Admin, + }; + const Model = roleModelMap[role]; + if (Model) { + Model.findById(userId) .then((user) => { if (user) { return done(null, user); @@ -44,6 +35,9 @@ passport.use( .catch((error) => { return done(error, false); }); + } else { + // Handle unknown roles + return done(null, false); } }) ); From a121d245624dd1885bab0de3ba189390c65b5b00 Mon Sep 17 00:00:00 2001 From: Samarth Vaidya Date: Tue, 15 Oct 2024 19:12:18 +0530 Subject: [PATCH 05/17] added layer of admin authentication --- backend/middlewares/authAdmin.js | 24 ++++++++++-------------- backend/routes/adminRouter.js | 1 + 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/backend/middlewares/authAdmin.js b/backend/middlewares/authAdmin.js index 39dc2baa..4f4ceba9 100644 --- a/backend/middlewares/authAdmin.js +++ b/backend/middlewares/authAdmin.js @@ -5,20 +5,16 @@ const authenticateAdmin = (req, res, next) => { const token = req.header("Authorization")?.split(" ")[1]; // Expecting "Bearer " if (token) { - jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => { - if (err) { - return res.sendStatus(403); // Forbidden - } - if (decoded.role !== "admin") { - return res.sendStatus(403); // Forbidden - } - - req.user = decoded; - logger.info(`Admin authenticated: ${JSON.stringify(decoded.id)}`); - next(); - }); - } else { - res.sendStatus(401); // Unauthorized + const decoded = jwt.verify(token, process.env.JWT_SECRET); + console.log(decoded.role); + if (decoded.role !== "admin") { + logger.error( + `Unauthorized access to admin route: ${JSON.stringify(decoded.id)}` + ); + return res.status(401).json({ error: "Unauthorized access" }); + } + logger.info(`Admin authenticated: ${JSON.stringify(decoded.sub)}`); + next(); } }; diff --git a/backend/routes/adminRouter.js b/backend/routes/adminRouter.js index 7f9bad13..de66f90f 100644 --- a/backend/routes/adminRouter.js +++ b/backend/routes/adminRouter.js @@ -8,6 +8,7 @@ require("dotenv").config(); router.get( "/", passport.authenticate("jwt", { session: false }), + authenticateAdmin, (req, res) => { res.json({ message: "Welcome to the Admin API!", From 6c3171d6fe9964a050b06d9041d81b60af4054e1 Mon Sep 17 00:00:00 2001 From: Samarth Vaidya Date: Tue, 15 Oct 2024 19:58:36 +0530 Subject: [PATCH 06/17] coderabbit changes 2.0 --- backend/middlewares/authAdmin.js | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/backend/middlewares/authAdmin.js b/backend/middlewares/authAdmin.js index 4f4ceba9..2c8eab9e 100644 --- a/backend/middlewares/authAdmin.js +++ b/backend/middlewares/authAdmin.js @@ -3,18 +3,24 @@ const logger = require("../config/logger"); const authenticateAdmin = (req, res, next) => { const token = req.header("Authorization")?.split(" ")[1]; // Expecting "Bearer " - if (token) { - const decoded = jwt.verify(token, process.env.JWT_SECRET); - console.log(decoded.role); - if (decoded.role !== "admin") { - logger.error( - `Unauthorized access to admin route: ${JSON.stringify(decoded.id)}` - ); + try { + const decoded = jwt.verify(token, process.env.JWT_SECRET); + console.log(decoded.role); + if (decoded.role !== "admin") { + logger.error( + `Unauthorized access to admin route: ${JSON.stringify(decoded.id)}` + ); + return res.status(401).json({ error: "Unauthorized access" }); + } + logger.info(`Admin authenticated: ${JSON.stringify(decoded.sub)}`); + next(); + } catch (error) { + logger.error(`Error authenticating admin: ${error}`); return res.status(401).json({ error: "Unauthorized access" }); } - logger.info(`Admin authenticated: ${JSON.stringify(decoded.sub)}`); - next(); + } else { + return res.status(401).json({ error: "No token was provided" }); } }; From a4f18fa3debae58f6eb0814504269a4ab320a435 Mon Sep 17 00:00:00 2001 From: Samarth Vaidya Date: Tue, 15 Oct 2024 19:59:42 +0530 Subject: [PATCH 07/17] coderabbit changes 2.0 --- backend/middlewares/authAdmin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/middlewares/authAdmin.js b/backend/middlewares/authAdmin.js index 2c8eab9e..a5e160ed 100644 --- a/backend/middlewares/authAdmin.js +++ b/backend/middlewares/authAdmin.js @@ -9,7 +9,7 @@ const authenticateAdmin = (req, res, next) => { console.log(decoded.role); if (decoded.role !== "admin") { logger.error( - `Unauthorized access to admin route: ${JSON.stringify(decoded.id)}` + `Unauthorized access to admin route: ${JSON.stringify(decoded.sub)}` ); return res.status(401).json({ error: "Unauthorized access" }); } From 5df6a14dbdc81d0b7edd8e3efa75b937d9ccf178 Mon Sep 17 00:00:00 2001 From: Samarth Vaidya Date: Tue, 15 Oct 2024 22:31:28 +0530 Subject: [PATCH 08/17] Implemented Google OAuth2.0 --- backend/.env.example | 5 ++- backend/config/oauth.config.js | 38 +++++++++++++++++++ backend/config/passport.config.js | 3 +- backend/config/secret.js | 4 ++ backend/controller/googleOAuth.controller.js | 26 +++++++++++++ backend/index.js | 9 +++++ backend/package.json | 1 + backend/routes/customerRouter.js | 6 +++ backend/routes/index.js | 9 ++++- frontend/src/components/Pages/Login.jsx | 40 ++++++++++---------- frontend/src/components/Pages/Signup.jsx | 5 +++ frontend/src/components/Shared/Navbar.jsx | 2 +- node_modules/.package-lock.json | 6 +++ 13 files changed, 131 insertions(+), 23 deletions(-) create mode 100644 backend/config/oauth.config.js create mode 100644 backend/controller/googleOAuth.controller.js create mode 100644 node_modules/.package-lock.json diff --git a/backend/.env.example b/backend/.env.example index 42b74fd4..b79381da 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -1,4 +1,7 @@ MONGO_URI=enter_your_mongo_uri EMAIL_USER=your_gmail EMAIL_PASS=your_16_digit_pass -JWT_SECRET=secret \ No newline at end of file +JWT_SECRET=secret +GOOGLE_CLIENT_ID=your_google_client_id +GOOGLE_CLIENT_SECRET=your_google_client_secret +FRONTEND_URL=your_frontend_url \ No newline at end of file diff --git a/backend/config/oauth.config.js b/backend/config/oauth.config.js new file mode 100644 index 00000000..a84e32c8 --- /dev/null +++ b/backend/config/oauth.config.js @@ -0,0 +1,38 @@ +const GoogleStrategy = require("passport-google-oauth20").Strategy; +const passport = require("passport"); +const Customer = require("../models/customer.model"); // Adjust the path as needed +const config = require("./secret"); // Import your secrets (client ID, client secret) + +passport.use( + new GoogleStrategy( + { + clientID: process.env.GOOGLE_CLIENT_ID || config.GOOGLE_CLIENT_ID, + clientSecret: + process.env.GOOGLE_CLIENT_SECRET || config.GOOGLE_CLIENT_SECRET, + callbackURL: "/auth/google/callback", + }, + async (accessToken, refreshToken, profile, done) => { + try { + // Extract the email from Google profile + const email = profile.emails[0].value; + + // Search for the user in the database by email + let user = await Customer.findOne({ email }); + if (!user) { + // If user doesn't exist, create a new user + user = new Customer({ + name: profile.displayName || "Unamed User", + email: email, // Email from Google profile + }); + await user.save(); + } + // Return the user if exists or after creation + return done(null, user); + } catch (error) { + return done(error, false); + } + } + ) +); + +module.exports = passport; diff --git a/backend/config/passport.config.js b/backend/config/passport.config.js index ec2bf4a1..15db45e0 100644 --- a/backend/config/passport.config.js +++ b/backend/config/passport.config.js @@ -4,12 +4,13 @@ const passport = require("passport"); const config = require("./secret"); const Customer = require("../models/customer.model"); const Admin = require("../models/admin.model"); +require("./oauth.config"); // Secret key to sign the JWT token const secret = config.JWT_SECRET; const opts = { jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), - secretOrKey: secret, + secretOrKey: process.env.JWT_SECRET || secret, }; passport.use( diff --git a/backend/config/secret.js b/backend/config/secret.js index 031c6a28..7dc86b62 100644 --- a/backend/config/secret.js +++ b/backend/config/secret.js @@ -2,10 +2,14 @@ const JWT_SECRET = process.env.JWT_SECRET; const MONGO_URI = process.env.MONGO_URI; const PORT = process.env.PORT; const CORS_ORIGIN = process.env.CORS_ORIGIN; +const GOOGLE_CLIENT_ID = process.env.GOOGLE_CLIENT_ID; +const GOOGLE_CLIENT_SECRET = process.env.GOOGLE_CLIENT_SECRET; module.exports = { JWT_SECRET, MONGO_URI, PORT, CORS_ORIGIN, + GOOGLE_CLIENT_ID, + GOOGLE_CLIENT_SECRET, }; diff --git a/backend/controller/googleOAuth.controller.js b/backend/controller/googleOAuth.controller.js new file mode 100644 index 00000000..1d3ca0ea --- /dev/null +++ b/backend/controller/googleOAuth.controller.js @@ -0,0 +1,26 @@ +const secret = require("../config/secret"); +const jwt = require("jsonwebtoken"); +const jwtSecret = process.env.JWT_SECRET || secret.JWT_SECRET; + +const handleGoogleOAuth = async (req, res) => { + const token = jwt.sign( + { + sub: req.user._id, + email: req.user.email, + }, + process.env.JWT_SECRET || jwtSecret, + { + expiresIn: "1d", + } + ); + + res.cookie("authToken", token, { + expire: "1h", + secure: true, + }); + res.redirect(process.env.FRONTEND_URL || "http://localhost:3000"); +}; + +module.exports = { + handleGoogleOAuth, +}; diff --git a/backend/index.js b/backend/index.js index 7092f588..fafda5cf 100644 --- a/backend/index.js +++ b/backend/index.js @@ -5,6 +5,7 @@ const dotenv = require("dotenv"); const logger = require("./config/logger"); const errorMiddleware = require("./middlewares/errrorMiddleware"); const passport = require("passport"); +const { handleGoogleOAuth } = require("./controller/googleOAuth.controller"); dotenv.config(); const app = express(); @@ -49,6 +50,14 @@ app.use(passport.initialize()); // API routes app.use("/api", require("./routes/index")); +app.get( + "/auth/google/callback", + passport.authenticate("google", { + failureRedirect: "/login", + session: false, + }), + handleGoogleOAuth +); app.options("*", cors(corsOptions)); diff --git a/backend/package.json b/backend/package.json index f77102a4..763337ac 100644 --- a/backend/package.json +++ b/backend/package.json @@ -23,6 +23,7 @@ "mongoose": "^8.7.0", "nodemailer": "^6.9.15", "passport": "^0.7.0", + "passport-google-oauth20": "^2.0.0", "passport-jwt": "^4.0.1", "validator": "^13.12.0", "winston": "^3.14.2", diff --git a/backend/routes/customerRouter.js b/backend/routes/customerRouter.js index 9fd05fb3..5a57513c 100644 --- a/backend/routes/customerRouter.js +++ b/backend/routes/customerRouter.js @@ -6,6 +6,7 @@ const { } = require("../controller/customer.controller"); const authenticateCustomer = require("../middlewares/authCustomer"); const passport = require("../config/passport.config"); +const { handleGoogleOAuth } = require("../controller/googleOAuth.controller"); const router = express.Router(); require("dotenv").config(); @@ -26,6 +27,11 @@ router.get( ); router.post("/register", createCustomer); +router.get( + "/auth/google", + passport.authenticate("google", { scope: ["email"] }) +); + router.post("/login", loginCustomer); router.post("/reset-password", resetPassword); diff --git a/backend/routes/index.js b/backend/routes/index.js index 63bcbbfb..cb87e8bf 100644 --- a/backend/routes/index.js +++ b/backend/routes/index.js @@ -1,5 +1,12 @@ const express = require("express"); const logger = require("../config/logger"); // Import your Winston logger +require("dotenv").config(); + +const config = { + JWT_SECRET: process.env.JWT_SECRET, + GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID, + GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET, +}; const router = express.Router(); @@ -46,6 +53,6 @@ router.use("/feedback", feedbackRouter); router.use("/user", require("./customerRouter")); router.use("/reservation", require("./reservationRouter")); router.use("/newsletter", require("./newsletterRoute")); -router.use("/forgot", require("./forgotRouter")) +router.use("/forgot", require("./forgotRouter")); module.exports = router; diff --git a/frontend/src/components/Pages/Login.jsx b/frontend/src/components/Pages/Login.jsx index 537c8f6b..47cc32c5 100644 --- a/frontend/src/components/Pages/Login.jsx +++ b/frontend/src/components/Pages/Login.jsx @@ -1,11 +1,10 @@ - -import React, { useState , useEffect } from "react"; -import photo from "../../assets/login.png"; -import { Link, useNavigate } from "react-router-dom"; -import { message } from "antd"; -import Cookies from 'js-cookie' -import { FaEye } from "react-icons/fa"; -import { FaEyeSlash } from "react-icons/fa6"; +import React, { useState, useEffect } from 'react'; +import photo from '../../assets/login.png'; +import { Link, useNavigate } from 'react-router-dom'; +import { message } from 'antd'; +import Cookies from 'js-cookie'; +import { FaEye } from 'react-icons/fa'; +import { FaEyeSlash } from 'react-icons/fa6'; const Login = () => { const API_URL = import.meta.env.VITE_BACKEND_URL || 'http://localhost:3000'; @@ -13,7 +12,7 @@ const Login = () => { email: '', password: '', }); - const [hidden, setHidden] = useState(true) + const [hidden, setHidden] = useState(true); const handleChange = (e) => { setData({ ...data, [e.target.name]: e.target.value }); @@ -39,9 +38,9 @@ const Login = () => { throw new Error(result.message || 'Login failed'); } // Handle successful login (e.g., store token, redirect) - Cookies.set('authToken',result.token,{ - expire:'1h', - secure:true + Cookies.set('authToken', result.token, { + expire: '1h', + secure: true, }); message.success('Login successful'); navigate('/'); @@ -83,17 +82,20 @@ const Login = () => { className="input w-full h-10 rounded-md border-2 border-black bg-beige shadow-[4px_4px_0px_0px_black] text-[15px] font-semibold text-[#323232] p-2.5 focus:outline-none focus:border-[#2d8cf0] placeholder-[#666] placeholder-opacity-80" name="password" placeholder="Password" - type={hidden ? "password" : "text"} + type={hidden ? 'password' : 'text'} onChange={(e) => handleChange(e)} /> -

- +
Forgot Password?
diff --git a/frontend/src/components/Pages/Signup.jsx b/frontend/src/components/Pages/Signup.jsx index 01170179..7eadb04d 100644 --- a/frontend/src/components/Pages/Signup.jsx +++ b/frontend/src/components/Pages/Signup.jsx @@ -168,6 +168,11 @@ const Signup = () => { {isLoading ? 'Loading...' : "Let's go →"} + + +
); }; diff --git a/frontend/src/components/Shared/Navbar.jsx b/frontend/src/components/Shared/Navbar.jsx index 4ae0f41b..2b7c1a24 100644 --- a/frontend/src/components/Shared/Navbar.jsx +++ b/frontend/src/components/Shared/Navbar.jsx @@ -177,7 +177,7 @@ const Navbar = () => {
{menuItems.map((item) => ( setIsMenuOpen((prev)=>!prev)} + onClick={() => setIsMenuOpen((prev) => !prev)} key={item.name} to={item.path} className={`block px-4 py-3 rounded-md text-base font-semibold transition duration-300 diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json new file mode 100644 index 00000000..a0c27c60 --- /dev/null +++ b/node_modules/.package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "PlayCafe", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} From ecb8b4de9434bde2017f9f3fd8990f5a664db29f Mon Sep 17 00:00:00 2001 From: Samarth Vaidya Date: Tue, 15 Oct 2024 22:43:06 +0530 Subject: [PATCH 09/17] Implemented Google OAuth2.0 --- frontend/src/components/Pages/Login.jsx | 13 ++++- frontend/src/components/Pages/Signup.jsx | 70 ++++++++++++++---------- 2 files changed, 54 insertions(+), 29 deletions(-) diff --git a/frontend/src/components/Pages/Login.jsx b/frontend/src/components/Pages/Login.jsx index 47cc32c5..c8428034 100644 --- a/frontend/src/components/Pages/Login.jsx +++ b/frontend/src/components/Pages/Login.jsx @@ -106,10 +106,21 @@ const Login = () => { Register Here + + + {error &&

{error}

} diff --git a/frontend/src/components/Pages/Signup.jsx b/frontend/src/components/Pages/Signup.jsx index 7eadb04d..3402aff1 100644 --- a/frontend/src/components/Pages/Signup.jsx +++ b/frontend/src/components/Pages/Signup.jsx @@ -1,11 +1,10 @@ - -import { useState , useEffect } from "react"; -import photo from "../../assets/login.png"; -import { useNavigate } from "react-router-dom"; -import { Link } from "react-router-dom"; -import { FaEye } from "react-icons/fa"; -import { FaEyeSlash } from "react-icons/fa6"; -import zxcvbn from "zxcvbn"; // Import zxcvbn for password strength check +import { useState, useEffect } from 'react'; +import photo from '../../assets/login.png'; +import { useNavigate } from 'react-router-dom'; +import { Link } from 'react-router-dom'; +import { FaEye } from 'react-icons/fa'; +import { FaEyeSlash } from 'react-icons/fa6'; +import zxcvbn from 'zxcvbn'; // Import zxcvbn for password strength check const Signup = () => { const API_URL = import.meta.env.VITE_BACKEND_URL || 'http://localhost:3000'; @@ -18,12 +17,12 @@ const Signup = () => { email: '', password: '', }); - const [hidden, setHidden] = useState(true) + const [hidden, setHidden] = useState(true); const handleChange = (e) => { setData({ ...data, [e.target.name]: e.target.value }); - if (e.target.name === "password") { + if (e.target.name === 'password') { const result = zxcvbn(e.target.value); setPasswordStrength(result.score); // Update password strength score } @@ -81,17 +80,17 @@ const Signup = () => { } }; - useEffect(() => { - window.scrollTo(0, 0); - }, []); + useEffect(() => { + window.scrollTo(0, 0); + }, []); const getPasswordStrengthColor = (score) => { - const colors = ["#ff4d4d", "#ff944d", "#ffd24d", "#d2ff4d", "#4dff88"]; + const colors = ['#ff4d4d', '#ff944d', '#ffd24d', '#d2ff4d', '#4dff88']; return colors[score]; }; const getPasswordStrengthText = (score) => { - const strengthLevels = ["Very Weak", "Weak", "Okay", "Good", "Strong"]; + const strengthLevels = ['Very Weak', 'Weak', 'Okay', 'Good', 'Strong']; return strengthLevels[score]; }; @@ -131,20 +130,29 @@ const Signup = () => { className="input w-full h-10 rounded-md border-2 border-black bg-beige shadow-[4px_4px_0px_0px_black] text-[15px] font-semibold text-[#323232] p-2.5 focus:outline-none focus:border-[#2d8cf0] placeholder-[#666] placeholder-opacity-80" name="password" placeholder="Password" - type={hidden ? "password" : "text"} + type={hidden ? 'password' : 'text'} onChange={(e) => handleChange(e)} /> -
{/* Password Strength Meter */}
-
+

Strength: {getPasswordStrengthText(passwordStrength)}

@@ -161,18 +169,24 @@ const Signup = () => { Login + + + - - -
); }; From f9cb18a0bfbaf8ab249ff4d612e10d8ca09df07d Mon Sep 17 00:00:00 2001 From: Ramakrushna Biswal <125277258+RamakrushnaBiswal@users.noreply.github.com> Date: Wed, 16 Oct 2024 07:21:59 +0530 Subject: [PATCH 10/17] Delete package-lock.json --- package-lock.json | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index a0c27c60..00000000 --- a/package-lock.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "PlayCafe", - "lockfileVersion": 3, - "requires": true, - "packages": {} -} From a88405b9bf655614d6f5c437c5e3c32b49f98027 Mon Sep 17 00:00:00 2001 From: Samarth Vaidya <128586929+samar12-rad@users.noreply.github.com> Date: Wed, 16 Oct 2024 09:10:42 +0530 Subject: [PATCH 11/17] Update backend/middlewares/authAdmin.js Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- backend/middlewares/authAdmin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/middlewares/authAdmin.js b/backend/middlewares/authAdmin.js index a5e160ed..41669522 100644 --- a/backend/middlewares/authAdmin.js +++ b/backend/middlewares/authAdmin.js @@ -6,7 +6,7 @@ const authenticateAdmin = (req, res, next) => { if (token) { try { const decoded = jwt.verify(token, process.env.JWT_SECRET); - console.log(decoded.role); + // Remove console.log or replace with logger.debug if needed if (decoded.role !== "admin") { logger.error( `Unauthorized access to admin route: ${JSON.stringify(decoded.sub)}` From 56238e53ed12a57f89b5fb67f39b77b65d62abc7 Mon Sep 17 00:00:00 2001 From: Samarth Vaidya Date: Wed, 16 Oct 2024 09:15:01 +0530 Subject: [PATCH 12/17] code rabbit changes --- backend/config/oauth.config.js | 3 ++- backend/config/passport.config.js | 1 + backend/config/secret.js | 2 ++ backend/controller/googleOAuth.controller.js | 9 ++++++--- backend/index.js | 4 +--- backend/middlewares/authAdmin.js | 8 ++------ backend/routes/index.js | 1 - frontend/src/components/Pages/Signup.jsx | 2 +- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/backend/config/oauth.config.js b/backend/config/oauth.config.js index a84e32c8..651df83c 100644 --- a/backend/config/oauth.config.js +++ b/backend/config/oauth.config.js @@ -29,7 +29,8 @@ passport.use( // Return the user if exists or after creation return done(null, user); } catch (error) { - return done(error, false); + console.error("Error during Google authentication:", error); + return done(null, false, { message: "Authentication failed" }); } } ) diff --git a/backend/config/passport.config.js b/backend/config/passport.config.js index 15db45e0..6bfae9ac 100644 --- a/backend/config/passport.config.js +++ b/backend/config/passport.config.js @@ -11,6 +11,7 @@ const secret = config.JWT_SECRET; const opts = { jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), secretOrKey: process.env.JWT_SECRET || secret, + algorithms: ["HS256"], }; passport.use( diff --git a/backend/config/secret.js b/backend/config/secret.js index 7dc86b62..793089f1 100644 --- a/backend/config/secret.js +++ b/backend/config/secret.js @@ -4,6 +4,7 @@ const PORT = process.env.PORT; const CORS_ORIGIN = process.env.CORS_ORIGIN; const GOOGLE_CLIENT_ID = process.env.GOOGLE_CLIENT_ID; const GOOGLE_CLIENT_SECRET = process.env.GOOGLE_CLIENT_SECRET; +const FRONTEND_URL = process.env.FRONTEND_URL; module.exports = { JWT_SECRET, @@ -12,4 +13,5 @@ module.exports = { CORS_ORIGIN, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, + FRONTEND_URL, }; diff --git a/backend/controller/googleOAuth.controller.js b/backend/controller/googleOAuth.controller.js index 1d3ca0ea..83541525 100644 --- a/backend/controller/googleOAuth.controller.js +++ b/backend/controller/googleOAuth.controller.js @@ -1,21 +1,24 @@ const secret = require("../config/secret"); const jwt = require("jsonwebtoken"); -const jwtSecret = process.env.JWT_SECRET || secret.JWT_SECRET; +const jwtSecret = secret.JWT_SECRET; const handleGoogleOAuth = async (req, res) => { const token = jwt.sign( { sub: req.user._id, email: req.user.email, + iat: Math.floor(Date.now() / 1000), + aud: "play-cafe", }, - process.env.JWT_SECRET || jwtSecret, + jwtSecret, { expiresIn: "1d", + algorithm: "HS256", } ); res.cookie("authToken", token, { - expire: "1h", + maxAge: 3600000, secure: true, }); res.redirect(process.env.FRONTEND_URL || "http://localhost:3000"); diff --git a/backend/index.js b/backend/index.js index fafda5cf..13f50cc8 100644 --- a/backend/index.js +++ b/backend/index.js @@ -1,13 +1,11 @@ const express = require("express"); +require("dotenv").config(); const cors = require("cors"); const mongoose = require("mongoose"); -const dotenv = require("dotenv"); const logger = require("./config/logger"); const errorMiddleware = require("./middlewares/errrorMiddleware"); const passport = require("passport"); const { handleGoogleOAuth } = require("./controller/googleOAuth.controller"); - -dotenv.config(); const app = express(); const port = process.env.PORT || 3000; diff --git a/backend/middlewares/authAdmin.js b/backend/middlewares/authAdmin.js index a5e160ed..ca04047e 100644 --- a/backend/middlewares/authAdmin.js +++ b/backend/middlewares/authAdmin.js @@ -8,15 +8,11 @@ const authenticateAdmin = (req, res, next) => { const decoded = jwt.verify(token, process.env.JWT_SECRET); console.log(decoded.role); if (decoded.role !== "admin") { - logger.error( - `Unauthorized access to admin route: ${JSON.stringify(decoded.sub)}` - ); - return res.status(401).json({ error: "Unauthorized access" }); + return res.status(401).json({ error: "Forbidden" }); } - logger.info(`Admin authenticated: ${JSON.stringify(decoded.sub)}`); + next(); } catch (error) { - logger.error(`Error authenticating admin: ${error}`); return res.status(401).json({ error: "Unauthorized access" }); } } else { diff --git a/backend/routes/index.js b/backend/routes/index.js index cb87e8bf..27a2b8bd 100644 --- a/backend/routes/index.js +++ b/backend/routes/index.js @@ -54,5 +54,4 @@ router.use("/user", require("./customerRouter")); router.use("/reservation", require("./reservationRouter")); router.use("/newsletter", require("./newsletterRoute")); router.use("/forgot", require("./forgotRouter")); - module.exports = router; diff --git a/frontend/src/components/Pages/Signup.jsx b/frontend/src/components/Pages/Signup.jsx index 3402aff1..a0ae4183 100644 --- a/frontend/src/components/Pages/Signup.jsx +++ b/frontend/src/components/Pages/Signup.jsx @@ -170,7 +170,7 @@ const Signup = () => {