diff --git a/backend/controllers/googleauth.js b/backend/controllers/googleauth.js new file mode 100644 index 0000000..9972f43 --- /dev/null +++ b/backend/controllers/googleauth.js @@ -0,0 +1,42 @@ +const { OAuth2Client } = require("google-auth-library"); +const User = require("../models/user"); + +const client = new OAuth2Client(process.env.GOOGLE_CLIENT_ID); + +exports.googleLogin = async (req, res) => { + try { + const { token } = req.body; + + const ticket = await client.verifyIdToken({ + idToken: token, + audience: process.env.GOOGLE_CLIENT_ID, + }); + + const payload = ticket.getPayload(); + const { email, name, picture, sub } = payload; + + let user = await User.findOne({ email }); + + if (!user) { + user = await User.create({ + email, + username: email.split("@")[0], + firstName: name.split(" ")[0], + lastName: name.split(" ").slice(1).join(" "), + profileImage: picture, + password: sub, + isGoogleUser: true, + }); + } + + const jwtToken = user.generateToken(); + + res.status(200).json({ + token: jwtToken, + user, + }); + } catch (err) { + console.error(err); + res.status(401).json({ message: "Google login failed" }); + } +}; diff --git a/backend/package.json b/backend/package.json index 69d9645..2c451ac 100644 --- a/backend/package.json +++ b/backend/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "description": "Smart Rent System - A MERN Stack Application", "main": "server.js", - "scripts": { + "scripts": { "server": "node server.js", "start": "node server.js", "dev": "concurrently \"node app.js\" \"cd client && npm run dev\"" @@ -23,9 +23,10 @@ "express": "^4.21.2", "express-mongo-sanitize": "^2.2.0", "express-session": "^1.18.1", + "google-auth-library": "^10.5.0", "helmet": "^8.1.0", "joi": "^17.13.3", - "jsonwebtoken": "^9.0.2", + "jsonwebtoken": "^9.0.3", "leaflet": "^1.9.4", "lucide-react": "^0.542.0", "method-override": "^3.0.0", diff --git a/backend/routes/userRoutes.js b/backend/routes/userRoutes.js index 41f8d93..13e134c 100644 --- a/backend/routes/userRoutes.js +++ b/backend/routes/userRoutes.js @@ -3,12 +3,15 @@ const router = express.Router(); const userController = require("../controllers/userController"); const { authenticate, authorize } = require("../middleware"); const { upload } = require("../cloudConfig"); +const { googleLogin } = require("../controllers/googleauth"); // Public routes router.post("/register", userController.registerUser); router.post("/login", userController.loginUser); router.post("/forgot-password", userController.forgotPassword); router.post("/reset-password/:token", userController.resetPassword); +router.post("/google", googleLogin); + // Protected routes router.post("/logout", authenticate, userController.logoutUser); diff --git a/frontend/package.json b/frontend/package.json index 57d5b8b..f2ac6eb 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -5,12 +5,13 @@ "proxy": "http://localhost:8000", "dependencies": { "@heroicons/react": "^2.2.0", + "@react-oauth/google": "^0.13.4", "@testing-library/dom": "^10.4.0", "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.2.0", "@testing-library/user-event": "^13.5.0", "autoprefixer": "^10.4.21", - "axios": "^1.8.4", + "axios": "^1.13.2", "leaflet": "1.9.4", "lucide-react": "^0.544.0", "node-fetch": "^3.3.2", diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 534aae8..62c9270 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -13,6 +13,7 @@ import PaymentPage from "./pages/PaymentPage"; import ResetPassword from "./pages/ResetPassword"; import ApiTest from "./pages/ApiTest"; import ProtectedRoute from "./components/ProtectedRoute"; +import Dashboard from "./pages/Dashboard"; function App() { return ( @@ -23,6 +24,7 @@ function App() { } /> } /> } /> + } /> } /> } /> } /> diff --git a/frontend/src/index.js b/frontend/src/index.js index 7e66f07..8fcd78c 100644 --- a/frontend/src/index.js +++ b/frontend/src/index.js @@ -3,6 +3,7 @@ import ReactDOM from "react-dom/client"; import "./index.css"; import App from "./App"; import reportWebVitals from "./reportWebVitals"; +import { GoogleOAuthProvider } from "@react-oauth/google"; // Reset scroll position on page load if (typeof window !== "undefined") { @@ -29,10 +30,14 @@ if (typeof window !== "undefined") { }); } +console.log("Google Client ID:", process.env.REACT_APP_GOOGLE_CLIENT_ID); + const root = ReactDOM.createRoot(document.getElementById("root")); root.render( - + + + ); diff --git a/frontend/src/pages/Dashboard.jsx b/frontend/src/pages/Dashboard.jsx new file mode 100644 index 0000000..72ab9f4 --- /dev/null +++ b/frontend/src/pages/Dashboard.jsx @@ -0,0 +1,12 @@ +import React from "react"; + +const Dashboard = () => { + return ( + + User Dashboard + Work in progress + + ); +}; + +export default Dashboard; diff --git a/frontend/src/pages/Login.jsx b/frontend/src/pages/Login.jsx index dadbd2e..e54b0ff 100644 --- a/frontend/src/pages/Login.jsx +++ b/frontend/src/pages/Login.jsx @@ -1,6 +1,9 @@ import React, { useState, useEffect } from "react"; import { Link, useNavigate, useLocation } from "react-router-dom"; import { useAuth } from "../contexts/AuthContext"; +import { GoogleLogin } from "@react-oauth/google"; +import axios from "axios"; + /** * Login Component @@ -122,32 +125,29 @@ const Login = () => { }; // Handle Google login - const handleGoogleLogin = async () => { + const handleGoogleLogin = async (res) => { setSocialLoading("google"); setError(""); try { - // Open Google OAuth popup - const googleAuthUrl = "https://accounts.google.com/o/oauth2/v2/auth"; - const redirectUri = window.location.origin + "/auth/google/callback"; + const googleToken = res.credential; - const params = new URLSearchParams({ - client_id: - process.env.REACT_APP_GOOGLE_CLIENT_ID || "your-google-client-id", - redirect_uri: redirectUri, - response_type: "code", - scope: "email profile", - prompt: "select_account", - }); + const response = await axios.post( + "http://localhost:8000/api/users/google", + { token: googleToken } + ); - // Open the Google login popup - window.location.href = `${googleAuthUrl}?${params.toString()}`; + localStorage.setItem("token", response.data.token); + navigate("/", { replace: true }); } catch (err) { - setError("Google login failed. Please try again."); + console.error(err); + setError("Google login failed"); + } finally { setSocialLoading(""); } }; + // Handle Facebook login const handleFacebookLogin = async () => { setSocialLoading("facebook"); @@ -434,41 +434,12 @@ const Login = () => { {/* Google login button */} - - Sign in with Google - {socialLoading === "google" ? ( - - ) : ( - - - - - - - )} - + setError("Google login failed")} + useOneTap + /> + {/* Facebook login button */}
Work in progress