diff --git a/GoogleAuth.md b/GoogleAuth.md new file mode 100644 index 00000000..550c42b5 --- /dev/null +++ b/GoogleAuth.md @@ -0,0 +1,41 @@ +Authentication (Google OAuth) + +This project uses Google OAuth 2.0 for user authentication via @react-oauth/google. + +``` +Setup Required +1. Create Google OAuth Client + -> Go to Google Cloud Console: + (https://console.cloud.google.com/apis/credentials?utm_source=chatgpt.com) + + -> Create OAuth Client ID + -> Choose Web application + +2. Configure Authorized Origins + ->Development + http://localhost:5173 (the port where your server is running i.e after running npm run dev) + ->Production + https://your-domain.com (the deployed url, only imp when you want the app to go live (not for your local computer)) + if working on local computer + the other javascript origin will be http://localhost + +3. Configure Redirect URIs + + ->Development + http://localhost:5173 + -> Production + https://your-domain.com (not necessary if you are not gonna deploy the app) + +``` + +Environment Variables +Create a .env file in the root: + +VITE_CLIENT_ID=your_google_client_id + +⚠️ This is required for Google login to work. + +`` + +That's it! +Google authentication will now work all fine ! \ No newline at end of file diff --git a/package.json b/package.json index 43ad31cc..556188f5 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,6 @@ "private": true, "version": "0.0.0", "type": "module", - "scripts": { "dev": "vite --host", "build": "vite build", @@ -14,17 +13,18 @@ "docker:dev": "docker compose --profile dev up --build", "docker:prod": "docker compose --profile prod up -d --build" }, - "dependencies": { "@emotion/react": "^11.11.3", "@emotion/styled": "^11.11.0", "@mui/icons-material": "^5.15.6", "@mui/material": "^5.15.6", "@primer/octicons-react": "^19.25.0", + "@react-oauth/google": "^0.13.5", "@vitejs/plugin-react": "^4.3.3", "axios": "^1.7.7", "express": "^5.2.1", "framer-motion": "^12.23.12", + "jwt-decode": "^4.0.0", "lucide-react": "^0.525.0", "mongoose": "^9.6.2", "octokit": "^4.0.2", @@ -37,7 +37,6 @@ "recharts": "^3.8.1", "tailwindcss": "^3.4.14" }, - "devDependencies": { "@eslint/js": "^9.13.0", "@testing-library/jest-dom": "^6.9.1", @@ -49,33 +48,22 @@ "@types/react-dom": "^18.3.7", "@types/react-redux": "^7.1.34", "@types/react-router-dom": "^5.3.3", - "@vitejs/plugin-react-swc": "^3.5.0", - "autoprefixer": "^10.4.20", "bcryptjs": "^3.0.3", - "eslint": "^9.13.0", "eslint-plugin-react": "^7.37.2", "eslint-plugin-react-hooks": "^5.0.0", "eslint-plugin-react-refresh": "^0.4.14", - "express-session": "^1.18.2", - "globals": "^15.11.0", - "jasmine": "^5.13.0", "jasmine-spec-reporter": "^7.0.0", - "jsdom": "^29.1.1", - "passport": "^0.7.0", "passport-local": "^1.0.0", - "supertest": "^7.2.2", - "typescript-eslint": "^8.59.3", - "vite": "^5.4.10", "vitest": "^4.1.6" } diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index fd5eac86..b2738a15 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -52,10 +52,20 @@ const Navbar: React.FC = () => { Contributors - + {localStorage.getItem("token") ? ( + + ) : ( Login + )} {/* Theme Toggle */} + ) : ( + + Login + + )} + + diff --git a/src/pages/Login/Login.tsx b/src/pages/Login/Login.tsx index 92b7073e..3676edf6 100644 --- a/src/pages/Login/Login.tsx +++ b/src/pages/Login/Login.tsx @@ -3,6 +3,8 @@ import axios from "axios"; import { useNavigate, Link } from "react-router-dom"; import { ThemeContext } from "../../context/ThemeContext"; import type { ThemeContextType } from "../../context/ThemeContext"; +import {jwtDecode} from "jwt-decode"; +import { GoogleLogin} from "@react-oauth/google"; const backendUrl = import.meta.env.VITE_BACKEND_URL; @@ -20,6 +22,7 @@ const Login: React.FC = () => { const themeContext = useContext(ThemeContext) as ThemeContextType; const { mode } = themeContext; + const handleChange = (e: ChangeEvent) => { const { name, value } = e.target; setFormData({ ...formData, [name]: value }); @@ -106,6 +109,7 @@ const Login: React.FC = () => { /> +
{ }`} />
- - +
+ { + const token = credentialResponse.credential; + if (!token) { + return; + } + try { + const res = await axios.post(`${backendUrl}/api/auth/google`, { credential: token }); + + localStorage.setItem("token", res.data.token); + + navigate("/"); + } catch (err) { + setMessage("Login failed. Please try again."); + + } + }} + /> +
{/* Message */} {message && (