Skip to content

Conversation

@aditiraj2006
Copy link
Contributor

@aditiraj2006 aditiraj2006 commented Aug 12, 2025

Related Issue


Description

Currently, the website’s authentication supports only email login. This update requests the addition of Google Login using Firebase Authentication, allowing users to sign in easily and securely with their Google accounts, alongside the existing email login.


How Has This Been Tested?

Manual Testing:

  • Enabled Google provider in the Firebase console.
  • Implemented logic using Firebase SDK in a local development environment.
  • Verified that logging in with both email and Google accounts works as expected.
  • Checked that authentication state is properly stored and reflected in the UI for each login method.

QA Checklist:

  • Google sign-in flow completes without errors or misrouting.
  • Users logging in with Google are recognized and session persists correctly.
  • Existing email login features remain functional and unaffected.
  • Edge cases (e.g., user denies Google consent, duplicate accounts) handled gracefully.

Screenshots

Screenshot 2025-08-12 203522 Screenshot 2025-08-12 203533 Screenshot 2025-08-12 203552

Type of Change

  • Bug fix
  • [✅] New feature
  • Code style update
  • Breaking change
  • Documentation update

Summary by CodeRabbit

  • New Features
    • Added Google Sign-In on Login and Signup pages for quick authentication.
  • Style
    • Introduced an “OR” divider and improved button visuals (hover and shadow effects) on auth pages.
  • Chores
    • Integrated Firebase-based authentication support and related dependencies.
    • Updated development server configuration to run on all interfaces at port 5173.

@netlify
Copy link

netlify bot commented Aug 12, 2025

Deploy Preview for github-spy ready!

Name Link
🔨 Latest commit 06466ad
🔍 Latest deploy log https://app.netlify.com/projects/github-spy/deploys/689b5a1c0713090008bc8ece
😎 Deploy Preview https://deploy-preview-190--github-spy.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 12, 2025

Walkthrough

Added Google Sign-In using Firebase on the frontend and a new backend endpoint to handle Google-based login/signup. Updated the user model to support googleId and optional password, integrated a GoogleSignIn component into Login/Signup pages, added Firebase config/hook, adjusted dev server config, and updated dependencies.

Changes

Cohort / File(s) Summary
Backend: User model updates
backend/models/User.js
Added googleId (unique, sparse); made password optional; removed unique from username; email remains required/unique.
Backend: Auth route
backend/routes/auth.js
Added POST /google-login to find-or-create user by email; stores googleId for new users; returns { message, user }.
Frontend: Firebase hook
src/hooks/firebase.ts
Initialized Firebase from env; exported auth and signInWithGoogle with local persistence and Google popup.
Frontend: Google Sign-In UI
src/components/GoogleSignIn.tsx
New component triggering Firebase Google sign-in, posts to backend, handles loading/navigation.
Frontend: Page integration
src/pages/Login/Login.tsx, src/pages/Signup/Signup.tsx
Inserted GoogleSignIn component with visual separators; no change to existing email flows.
Config: Vite dev server
vite.config.ts
Added server host 0.0.0.0 and port 5173.
Dependencies
package.json
Added firebase, react-firebase-hooks, and i to dependencies.
Misc: Formatting
src/App.tsx
Added a leading blank line (no functional change).

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant UI as Frontend (GoogleSignIn)
  participant Firebase as Firebase Auth
  participant API as Backend /api/auth/google-login
  participant DB as DB (Users)

  User->>UI: Click "Sign in with Google"
  UI->>Firebase: signInWithPopup(Google)
  Firebase-->>UI: UserCredential (email, displayName, uid)
  UI->>API: POST /google-login { email, name, googleId }
  API->>DB: Find user by email
  alt User exists
    DB-->>API: Existing user
    API-->>UI: { message: "Login successful", user }
  else User not found
    API->>DB: Create user with email, username=name, googleId
    DB-->>API: New user
    API-->>UI: { message: "Login successful", user }
  end
  UI-->>User: Navigate to home
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Assessment against linked issues

Objective Addressed Explanation
Integrate Firebase SDK in project (#154)
Add “Sign in with Google” button and initiate flow on click (#154)
Enable Google as a Provider in Firebase Console (#154) Requires console configuration; not verifiable in code.
Handle auth state and multiple login methods (#154) Persistence set, but no global auth state/session handling shown.
Optional: Merge accounts for duplicate emails (#154) Existing users by email are not updated to set googleId or merge profiles.

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
Removed unique constraint from username (backend/models/User.js: n/a) Not specified in the issue; alters data constraints beyond Google login necessity.
Added dependency "i" (package.json: n/a) Unrelated to Firebase/Google auth; not used in the provided code.
Added dependency "react-firebase-hooks" (package.json: n/a) Not used in the current implementation.
Vite server host/port config (vite.config.ts: n/a) Dev server networking change not mentioned in the issue.

Poem

I thump with glee at login doors,
A carrot-click—Google soars!
Firebase whispers, “You’re all set,”
Backend nods, “We’ve safely met.”
No passwords lost, no burrow stress—
Hop on in, enjoy the nest! 🥕✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (3)
src/hooks/firebase.ts (1)

15-17: Ensure account selection prompt for better UX

Trigger Google account chooser on every login to avoid sticky sessions picking a prior account.

Apply:

 const auth = getAuth(app);
 const googleAuthProvider = new GoogleAuthProvider();
+googleAuthProvider.setCustomParameters({ prompt: 'select_account' });
src/App.tsx (1)

1-1: Remove leading blank line to satisfy common linters

No functional change, but many configs flag leading blank lines at file start.

-
 import Navbar from "./components/Navbar";
src/pages/Signup/Signup.tsx (1)

158-158: Minor: Remove unnecessary empty line.

The extra blank line after the message div is unnecessary and inconsistent with the surrounding code formatting.

-            
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 00a00d6 and 06466ad.

📒 Files selected for processing (9)
  • backend/models/User.js (1 hunks)
  • backend/routes/auth.js (2 hunks)
  • package.json (1 hunks)
  • src/App.tsx (1 hunks)
  • src/components/GoogleSignIn.tsx (1 hunks)
  • src/hooks/firebase.ts (1 hunks)
  • src/pages/Login/Login.tsx (2 hunks)
  • src/pages/Signup/Signup.tsx (3 hunks)
  • vite.config.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/components/GoogleSignIn.tsx (1)
src/hooks/firebase.ts (1)
  • signInWithGoogle (23-23)
backend/routes/auth.js (1)
backend/config/passportConfig.js (3)
  • user (10-10)
  • user (40-40)
  • User (3-3)
🔇 Additional comments (8)
src/pages/Login/Login.tsx (2)

6-7: GoogleSignIn wiring looks good

Import placement and usage align with the new auth flow.


128-128: Button styling change is safe

UI-only enhancement; no impact on logic.

backend/models/User.js (2)

17-21: LGTM! Google ID field properly configured.

The googleId field is well-configured with appropriate constraints:

  • unique: true ensures no duplicate Google accounts
  • sparse: true allows multiple users without Google IDs (null values)
  • Optional field supports both Google and email/password users

5-8: Username uniqueness requirements verified—no dependencies found.
Our search across JS/TS files and AST patterns didn’t uncover any code that assumes or enforces username uniqueness. Removing the unique: true constraint is safe in the current codebase.

src/pages/Signup/Signup.tsx (2)

5-5: LGTM! Clean integration of Google Sign-In component.

The import is properly structured and the component integration follows React best practices.


137-147: LGTM! Well-designed UI integration with proper visual separation.

The OR separator and Google Sign-In button integration maintains good UX with:

  • Clear visual separation between authentication methods
  • Consistent styling with the existing form
  • Proper component encapsulation
src/components/GoogleSignIn.tsx (2)

1-6: LGTM! Clean imports and environment configuration.

The imports are well-organized and the environment variable usage for backend URL is appropriate for configuration management.


49-57: LGTM! Well-designed button component with proper accessibility.

The button implementation includes:

  • Proper loading state management
  • Accessibility features (disabled state)
  • Consistent styling with the application theme
  • Good user feedback with loading text

Comment on lines +14 to +16
password: {
type: String,
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Potential runtime errors in password hashing for Google users.

Making the password field optional could cause issues in the pre-save hook (lines 25-37) and comparePassword method (lines 40-41), as these assume a password exists and attempt to hash/compare undefined values.

Apply this diff to handle optional passwords properly:

 UserSchema.pre('save', async function (next) {
-    if (!this.isModified('password'))
+    if (!this.isModified('password') || !this.password)
         return next();

     try {
       const salt = await bcrypt.genSalt(10);
       this.password = await bcrypt.hash(this.password, salt);
       next();
     } catch (err) {
       return next(err);
     }
 });

 // Compare passwords during login
 UserSchema.methods.comparePassword = async function (enteredPassword) {
+    if (!this.password) {
+        return false;
+    }
     return await bcrypt.compare(enteredPassword, this.password);
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
password: {
type: String,
},
UserSchema.pre('save', async function (next) {
// Only hash if the password was modified and actually exists
if (!this.isModified('password') || !this.password) {
return next();
}
try {
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(this.password, salt);
next();
} catch (err) {
return next(err);
}
});
// Compare passwords during login
UserSchema.methods.comparePassword = async function (enteredPassword) {
// If there's no stored password (e.g. OAuth user), always fail comparison
if (!this.password) {
return false;
}
return await bcrypt.compare(enteredPassword, this.password);
};
🤖 Prompt for AI Agents
In backend/models/User.js around lines 14 to 16 (and affecting the pre-save hook
at ~25-37 and comparePassword at ~40-41), the schema makes password optional but
the pre-save hook and comparePassword assume a defined password; update them so
the pre-save hook only runs hashing when this.isModified('password') &&
this.password is truthy, and skip hashing for users without a password (e.g.,
Google OAuth). Also change comparePassword to immediately return false (or a
rejected Promise) if the stored password is falsy, and only call bcrypt.compare
when both the candidate password and stored hash exist; keep the same
async/callback pattern used elsewhere. This prevents attempts to hash/compare
undefined values for OAuth users.

Comment on lines +30 to +53
router.post("/google-login", async (req, res) => {
try {
const { email, name, googleId } = req.body;

let user = await User.findOne({ email });

if (!user) {
user = new User({
username: name,
email,
googleId,
});
await user.save();
console.log("New Google user saved:", user);
} else {
console.log("Google user found:", user);
}

return res.json({ message: "Login successful", user });
} catch (error) {
console.error("Google login error:", error);
return res.status(500).json({ message: "Server error" });
}
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Critical security and account management issues need to be addressed.

The Google login endpoint has several critical issues:

  1. Account security vulnerability: When finding an existing user by email, the endpoint doesn't verify the googleId matches, potentially allowing account takeover if someone knows another user's email.

  2. Missing account linking: If a user exists with email/password but no googleId, the endpoint doesn't update their record to link the Google account.

  3. No authentication state management: Unlike the Passport-based /login route, this endpoint doesn't establish a session or provide authentication context.

Apply this diff to fix the security and account management issues:

 router.post("/google-login", async (req, res) => {
   try {
     const { email, name, googleId } = req.body;

     let user = await User.findOne({ email });

     if (!user) {
       user = new User({
         username: name,
         email,
         googleId,
       });
       await user.save();
       console.log("New Google user saved:", user); 
     } else {
-      console.log("Google user found:", user);
+      // Link Google account if not already linked
+      if (!user.googleId) {
+        user.googleId = googleId;
+        await user.save();
+        console.log("Google account linked to existing user:", user);
+      } else if (user.googleId !== googleId) {
+        return res.status(400).json({ message: "Email is associated with a different Google account" });
+      } else {
+        console.log("Google user found:", user);
+      }
     }

+    // Establish session like the regular login route
+    req.login(user, (err) => {
+      if (err) {
+        return res.status(500).json({ message: "Session creation failed" });
+      }
       return res.json({ message: "Login successful", user });
+    });
   } catch (error) {
     console.error("Google login error:", error);
     return res.status(500).json({ message: "Server error" });
   }
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
router.post("/google-login", async (req, res) => {
try {
const { email, name, googleId } = req.body;
let user = await User.findOne({ email });
if (!user) {
user = new User({
username: name,
email,
googleId,
});
await user.save();
console.log("New Google user saved:", user);
} else {
console.log("Google user found:", user);
}
return res.json({ message: "Login successful", user });
} catch (error) {
console.error("Google login error:", error);
return res.status(500).json({ message: "Server error" });
}
});
router.post("/google-login", async (req, res) => {
try {
const { email, name, googleId } = req.body;
let user = await User.findOne({ email });
if (!user) {
user = new User({
username: name,
email,
googleId,
});
await user.save();
console.log("New Google user saved:", user);
} else {
// Link Google account if not already linked
if (!user.googleId) {
user.googleId = googleId;
await user.save();
console.log("Google account linked to existing user:", user);
} else if (user.googleId !== googleId) {
return res
.status(400)
.json({ message: "Email is associated with a different Google account" });
} else {
console.log("Google user found:", user);
}
}
// Establish session like the regular login route
req.login(user, (err) => {
if (err) {
return res
.status(500)
.json({ message: "Session creation failed" });
}
return res.json({ message: "Login successful", user });
});
} catch (error) {
console.error("Google login error:", error);
return res
.status(500)
.json({ message: "Server error" });
}
});
🤖 Prompt for AI Agents
In backend/routes/auth.js around lines 30 to 53, the Google login handler
currently trusts email alone and neither verifies the googleId nor links
accounts or establishes auth state; update it to first validate incoming payload
(email and googleId), then lookup User by email and: if found and user.googleId
exists, ensure it matches the provided googleId and reject with 401 on mismatch;
if found and user.googleId is absent, set user.googleId to the provided value
and save to link the Google account; if not found, create a new user with
googleId and save; after any successful lookup or creation, establish an
authenticated session identical to your /login flow (e.g., call req.login or
issue the same JWT/session cookie you use elsewhere) and return the user without
sensitive fields, while returning appropriate 4xx errors for invalid payloads
and mismatched googleId to prevent account takeover.

Comment on lines +22 to 31
"firebase": "^12.1.0",
"framer-motion": "^12.23.12",
"i": "^0.3.7",
"lucide-react": "^0.525.0",
"octokit": "^4.0.2",
"postcss": "^8.4.47",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-firebase-hooks": "^5.1.1",
"react-hot-toast": "^2.4.1",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify and remove potentially unused or unintended dependencies ("i", "react-firebase-hooks")

The newly added "i" and "react-firebase-hooks" packages don’t appear in the provided code paths. If unused, they increase install size and attack surface.

Run this to confirm usage:

If unused, remove them:

   "dependencies": {
     ...
-    "firebase": "^12.1.0",
+    "firebase": "^12.1.0",
     ...
-    "i": "^0.3.7",
+    // "i" removed if unused
     ...
-    "react-firebase-hooks": "^5.1.1",
+    // "react-firebase-hooks" removed if unused
     ...
   },

🏁 Script executed:

#!/bin/bash
# Find direct imports/usages of 'i' and 'react-firebase-hooks'
rg -n -S $'from [\'"]i[\'"]|require\\([\'"]i[\'"]\\)' || true
rg -n -S 'react-firebase-hooks' || true

Length of output: 153


Remove unused dependencies “i” and “react-firebase-hooks”
A project-wide search found no imports or requires for these two packages beyond their entries in package.json. Removing them will slim install size and reduce attack surface.

• package.json – lines for
– “i” (^0.3.7)
– “react-firebase-hooks” (^5.1.1)

Suggested diff:

   "dependencies": {
     "firebase": "^12.1.0",
     "framer-motion": "^12.23.12",
-    "i": "^0.3.7",
-    "react-firebase-hooks": "^5.1.1",
     "lucide-react": "^0.525.0",
     "octokit": "^4.0.2",
     …
   },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"firebase": "^12.1.0",
"framer-motion": "^12.23.12",
"i": "^0.3.7",
"lucide-react": "^0.525.0",
"octokit": "^4.0.2",
"postcss": "^8.4.47",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-firebase-hooks": "^5.1.1",
"react-hot-toast": "^2.4.1",
"dependencies": {
"firebase": "^12.1.0",
"framer-motion": "^12.23.12",
"lucide-react": "^0.525.0",
"octokit": "^4.0.2",
"postcss": "^8.4.47",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hot-toast": "^2.4.1",
},
🤖 Prompt for AI Agents
In package.json around lines 22 to 31, remove the unused dependency entries for
"i" (^0.3.7) and "react-firebase-hooks" (^5.1.1) from the dependencies section,
then run your package manager to update the lockfile (npm install or yarn
install) and commit the updated package.json and lockfile; after that run the
test/build steps to ensure nothing breaks and update any CI cache if necessary.

Comment on lines +12 to +47
const handleSignIn = async () => {
setIsLoading(true);
try {
const userCredential = await signInWithGoogle();
console.log("Google userCredential:", userCredential);

if (userCredential && userCredential.user) {
const idToken = await userCredential.user.getIdToken();
const { email, displayName, uid } = userCredential.user;
console.log("Google user info:", { email, displayName, uid });

const response = await axios.post(
`${backendUrl}/api/auth/google-login`,
{
email,
name: displayName,
googleId: uid,
}
);
console.log("Backend response:", response.data);

if (response.data.message === "Login successful") {
navigate("/");
} else {
alert(response.data.message || "Google login failed");
}
} else {
alert("No user returned from Google sign-in");
}
} catch (error) {
console.error("Google sign-in error:", error);
alert("Google sign-in failed");
} finally {
setIsLoading(false);
}
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Several improvements needed for production readiness.

The core authentication flow is functional but has areas for improvement:

  1. Unused ID token: The idToken is retrieved but never used, which may indicate incomplete Firebase authentication verification.

  2. User experience: Using alert() for error messages is not ideal for modern web applications - consider using toast notifications or inline error states.

  3. Error handling: Generic error messages don't help users understand specific issues (network failures, auth cancellation, etc.).

  4. Security consideration: The backend endpoint lacks proper session management (see backend review comments).

Consider these improvements for better UX and security:

   const handleSignIn = async () => {
     setIsLoading(true);
     try {
       const userCredential = await signInWithGoogle();
       console.log("Google userCredential:", userCredential);

       if (userCredential && userCredential.user) {
-        const idToken = await userCredential.user.getIdToken();
         const { email, displayName, uid } = userCredential.user;
         console.log("Google user info:", { email, displayName, uid });

         const response = await axios.post(
           `${backendUrl}/api/auth/google-login`,
           {
             email,
             name: displayName,
             googleId: uid,
           }
         );
         console.log("Backend response:", response.data);

         if (response.data.message === "Login successful") {
           navigate("/");
         } else {
-          alert(response.data.message || "Google login failed");
+          // TODO: Replace with proper error state or toast notification
+          console.error("Login failed:", response.data.message);
         }
       } else {
-        alert("No user returned from Google sign-in");
+        console.error("No user returned from Google sign-in");
       }
     } catch (error) {
       console.error("Google sign-in error:", error);
-      alert("Google sign-in failed");
+      // TODO: Handle specific error types (user cancelled, network error, etc.)
     } finally {
       setIsLoading(false);
     }
   };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleSignIn = async () => {
setIsLoading(true);
try {
const userCredential = await signInWithGoogle();
console.log("Google userCredential:", userCredential);
if (userCredential && userCredential.user) {
const idToken = await userCredential.user.getIdToken();
const { email, displayName, uid } = userCredential.user;
console.log("Google user info:", { email, displayName, uid });
const response = await axios.post(
`${backendUrl}/api/auth/google-login`,
{
email,
name: displayName,
googleId: uid,
}
);
console.log("Backend response:", response.data);
if (response.data.message === "Login successful") {
navigate("/");
} else {
alert(response.data.message || "Google login failed");
}
} else {
alert("No user returned from Google sign-in");
}
} catch (error) {
console.error("Google sign-in error:", error);
alert("Google sign-in failed");
} finally {
setIsLoading(false);
}
};
const handleSignIn = async () => {
setIsLoading(true);
try {
const userCredential = await signInWithGoogle();
console.log("Google userCredential:", userCredential);
if (userCredential && userCredential.user) {
const { email, displayName, uid } = userCredential.user;
console.log("Google user info:", { email, displayName, uid });
const response = await axios.post(
`${backendUrl}/api/auth/google-login`,
{
email,
name: displayName,
googleId: uid,
}
);
console.log("Backend response:", response.data);
if (response.data.message === "Login successful") {
navigate("/");
} else {
// TODO: Replace with proper error state or toast notification
console.error("Login failed:", response.data.message);
}
} else {
console.error("No user returned from Google sign-in");
}
} catch (error) {
console.error("Google sign-in error:", error);
// TODO: Handle specific error types (user cancelled, network error, etc.)
} finally {
setIsLoading(false);
}
};
🤖 Prompt for AI Agents
In src/components/GoogleSignIn.tsx around lines 12 to 47, the handler retrieves
an idToken but never uses it and shows raw alerts on errors; update the flow to
send the idToken to the backend (either in the POST body or Authorization
header) so the server can verify the Firebase token and establish a session,
replace alert() calls with a UI-friendly error mechanism (toast or component
state like setError and render inline messages), and improve error handling by
distinguishing Axios/network errors, Firebase auth cancellations, and unexpected
exceptions to display meaningful messages and log full error details; keep
setIsLoading(false) in finally.

Comment on lines +4 to +11
const firebaseConfig = {
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
appId: import.meta.env.VITE_FIREBASE_APP_ID
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Fail fast if required Firebase env vars are missing

InitializeApp will throw opaque errors later if any of these are undefined. Guard early with a clear message.

Apply this check:

 const firebaseConfig = {
   apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
   authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
   projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
   storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
   messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
   appId: import.meta.env.VITE_FIREBASE_APP_ID
 };
+
+const missing = Object.entries(firebaseConfig)
+  .filter(([, v]) => !v)
+  .map(([k]) => k);
+if (missing.length) {
+  throw new Error(`Missing Firebase env vars: ${missing.join(", ")}`);
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const firebaseConfig = {
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
appId: import.meta.env.VITE_FIREBASE_APP_ID
};
const firebaseConfig = {
apiKey: import.meta.env.VITE_FIREBASE_API_KEY,
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN,
projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID,
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET,
messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID,
appId: import.meta.env.VITE_FIREBASE_APP_ID
};
const missing = Object.entries(firebaseConfig)
.filter(([, v]) => !v)
.map(([k]) => k);
if (missing.length) {
throw new Error(`Missing Firebase env vars: ${missing.join(", ")}`);
}
🤖 Prompt for AI Agents
In src/hooks/firebase.ts around lines 4 to 11, the firebaseConfig is built
directly from import.meta.env so missing env vars cause opaque errors later; add
a guard that enumerates the required variable names, checks import.meta.env for
each, collects any missing keys, and if any are missing throw (or console.error
then throw) a clear Error listing which env vars are absent (and stop
initialization). Run this check before using firebaseConfig or calling
initializeApp so the failure is immediate and the error message is actionable.

Comment on lines +18 to +21
const signInWithGoogle = async () => {
await setPersistence(auth, browserLocalPersistence);
return await signInWithPopup(auth, googleAuthProvider);
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Critical: Send and verify Firebase ID token on the backend; don’t trust client-supplied UID/email

The current flow returns a UserCredential to the caller, which then posts uid/email to your backend (per PR description). Without verifying an ID token server-side, an attacker can spoof uid/email. The backend must verify a Firebase ID token using the Admin SDK (or Google’s token verification) before creating/authenticating a user.

Refactor to return the ID token alongside the credential so the frontend can send it to the backend:

-const signInWithGoogle = async () => {
-  await setPersistence(auth, browserLocalPersistence);
-  return await signInWithPopup(auth, googleAuthProvider);
-};
+const signInWithGoogle = async () => {
+  await setPersistence(auth, browserLocalPersistence);
+  const cred = await signInWithPopup(auth, googleAuthProvider);
+  const idToken = await cred.user.getIdToken();
+  return { cred, idToken };
+};

Then, POST the idToken to the backend (e.g., in GoogleSignIn.tsx) and verify it there with Firebase Admin before trusting any user claims.

Optionally add a popup fallback for Safari/mobile:

-import { getAuth, GoogleAuthProvider, signInWithPopup, setPersistence, browserLocalPersistence } from 'firebase/auth';
+import { getAuth, GoogleAuthProvider, signInWithPopup, signInWithRedirect, setPersistence, browserLocalPersistence } from 'firebase/auth';
...
-  const cred = await signInWithPopup(auth, googleAuthProvider);
+  let cred;
+  try {
+    cred = await signInWithPopup(auth, googleAuthProvider);
+  } catch (e: any) {
+    if (e?.code === 'auth/popup-blocked' || e?.code === 'auth/cancelled-popup-request') {
+      await signInWithRedirect(auth, googleAuthProvider);
+      return { cred: undefined, idToken: undefined }; // handle redirect result in caller if you add it
+    }
+    throw e;
+  }

Confirm the backend’s /google-login endpoint verifies a Firebase ID token (not raw uid/email) using the Firebase Admin SDK before creating/authenticating users. If not, this is a blocker to merge.


🏁 Script executed:

#!/bin/bash
# Search for the /google-login handler in the server code
rg -n "google-login"
# Search for Firebase Admin SDK token verification calls
rg -n "verifyIdToken"
rg -n "auth().verifyIdToken"
# Search for any use of firebase-admin in server dependencies
grep -R "firebase-admin" -n .

Length of output: 264


🏁 Script executed:

#!/bin/bash
# Display the /google-login handler implementation to verify ID token verification
sed -n '1,200p' backend/routes/auth.js

Length of output: 1851


Critical: Implement Firebase ID Token Verification in google-login Endpoint

The backend currently trusts client-supplied email/googleId without verifying the Firebase ID token. This allows attackers to spoof identities. You must:

• Frontend (src/hooks/firebase.ts)

  • Return the user’s ID token alongside the credential:
    const signInWithGoogle = async () => {
      await setPersistence(auth, browserLocalPersistence);
    - return await signInWithPopup(auth, googleAuthProvider);
    + const cred = await signInWithPopup(auth, googleAuthProvider);
    + const idToken = await cred.user.getIdToken();
    + return { cred, idToken };
    };
  • Send idToken (not raw UID/email) in your POST to /api/auth/google-login.

• Backend (backend/routes/auth.js)

  1. Install & initialize the Firebase Admin SDK:
    // at top of file
    const admin = require('firebase-admin');
    admin.initializeApp({
      credential: admin.credential.cert(require('../path/to/serviceAccountKey.json')),
    });
  2. Verify the ID token in /google-login before trusting any claims:
    router.post("/google-login", async (req, res) => {
      try {
-    const { email, name, googleId } = req.body;
+    const { idToken } = req.body;
+    const decoded = await admin.auth().verifyIdToken(idToken);
+    const { uid, email, name } = decoded;

     let user = await User.findOne({ email });
     if (!user) {
       user = new User({ username: name, email, googleId: uid });
       await user.save();
     }

     return res.json({ message: "Login successful", user });
   } catch (error) {
     console.error("Google login error:", error);
     return res.status(401).json({ message: "Invalid or expired token" });
   }
 });
 ```

Please implement these changes before merging.

🤖 Prompt for AI Agents
In src/hooks/firebase.ts around lines 18-21, you need to return the Firebase ID
token from signInWithGoogle and ensure the frontend sends that idToken (not raw
uid/email) in the POST to /api/auth/google-login; modify signInWithGoogle to
obtain and return user.getIdToken() (or equivalent) alongside the credential so
the caller can include idToken in the request body. On the backend
(backend/routes/auth.js) add and initialize the Firebase Admin SDK (require
firebase-admin, initializeApp with service account credential) near the top of
the file, then in the /google-login handler verify the received idToken with
admin.auth().verifyIdToken(idToken) and only trust claims (uid/email) from the
verified token result before creating or logging in the user; reject requests
with invalid or missing tokens with a 401.

Comment on lines +132 to +141
<div className="flex items-center my-4">
<div className="flex-grow h-px bg-gray-300" />
<span className="mx-4 text-gray-500 font-semibold">or</span>
<div className="flex-grow h-px bg-gray-300" />
</div>

{/* Google Sign-In Button */}
<div>
<GoogleSignIn />
</div>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Unify post-login navigation and error handling across password and Google flows

Password login navigates to "/home" and surfaces messages in-form; GoogleSignIn (per summary) navigates to "/" and uses alerts. For consistency and better UX, pass callbacks so GoogleSignIn uses the same messaging and destination.

Apply:

-            <div>
-              <GoogleSignIn />
-            </div>
+            <div>
+              <GoogleSignIn
+                onSuccess={() => navigate("/home")}
+                onError={(msg: string) => setMessage(msg || "Something went wrong")}
+              />
+            </div>

Follow-up: update GoogleSignIn to accept optional onSuccess/onError props and to surface backend responses via these instead of alert().

Ensure CORS is configured on the backend to allow the frontend origin (e.g., http://localhost:5173) for the /api/auth/google-login endpoint.


🏁 Script executed:

#!/bin/bash
# Find all occurrences of GoogleSignIn in the codebase
rg "GoogleSignIn" -n src

# Locate the import in Login.tsx
rg "import .*GoogleSignIn" -n src/pages/Login/Login.tsx

# Search for the component definition
rg -n "export (default )?function GoogleSignIn" -n src

Length of output: 624


Unify post-login navigation and error handling across password and Google flows

  • In src/pages/Login/Login.tsx, update the GoogleSignIn usage to pass the same callbacks you use for the password flow:
     <div>
  • <GoogleSignIn
  •  onSuccess={() => navigate("/home")}
    
  •  onError={(msg: string) => setMessage(msg || "Something went wrong")}
    
  • />
``` - In **src/components/GoogleSignIn.tsx**, extend the component’s props to accept optional `onSuccess` and `onError` callbacks. Replace any direct `navigate("/")` or `alert()` calls with these props: - Call `onSuccess()` on a successful sign-in - Call `onError(errorMessage)` on failure - (Optional) Mirror this change in **src/pages/Signup/Signup.tsx** to keep signup and login consistent. - Ensure your backend’s CORS policy allows your frontend origin (e.g., http://localhost:5173) to call `/api/auth/google-login`.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<div className="flex items-center my-4">
<div className="flex-grow h-px bg-gray-300" />
<span className="mx-4 text-gray-500 font-semibold">or</span>
<div className="flex-grow h-px bg-gray-300" />
</div>
{/* Google Sign-In Button */}
<div>
<GoogleSignIn />
</div>
<div className="flex items-center my-4">
<div className="flex-grow h-px bg-gray-300" />
<span className="mx-4 text-gray-500 font-semibold">or</span>
<div className="flex-grow h-px bg-gray-300" />
</div>
{/* Google Sign-In Button */}
<div>
<GoogleSignIn
onSuccess={() => navigate("/home")}
onError={(msg: string) => setMessage(msg || "Something went wrong")}
/>
</div>
🤖 Prompt for AI Agents
In src/pages/Login/Login.tsx around lines 132-141, the GoogleSignIn usage needs
to be updated to accept the same post-login navigation and error handling
callbacks as the password flow: change the <GoogleSignIn /> invocation to pass
the existing onSuccess and onError handlers (or the functions used by the
password flow that call navigate("/") and show errors) so both flows behave
identically; in src/components/GoogleSignIn.tsx add optional props onSuccess?:
() => void and onError?: (msg: string) => void, remove any direct navigate("/")
or alert() calls, and instead call onSuccess() on successful sign-in or
onError(errorMessage) on failure; optionally apply the same change to
src/pages/Signup/Signup.tsx for parity; also verify backend CORS permits the
frontend origin (e.g., http://localhost:5173) to call /api/auth/google-login.

Comment on lines +7 to +10
server:{
host:'0.0.0.0',
port:5173
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

❓ Verification inconclusive

Parameterize dev server host/port and avoid binding to all interfaces by default

Binding to 0.0.0.0 exposes your dev server to the LAN. Prefer localhost by default and allow overrides via env for multi-device testing. Also avoids duplicating host config with the "vite --host" script.

Apply this minimal change to make host/port configurable:

   server:{
-    host:'0.0.0.0',
-    port:5173
+    host: process.env.VITE_DEV_HOST ?? 'localhost',
+    port: Number(process.env.VITE_DEV_PORT ?? 5173)
   }

Ensure Firebase Authentication’s Authorized domains include the dev URL you’ll actually visit in the browser (e.g., http://localhost:5173). If you plan to use a LAN IP, add that domain too.


Parameterize Vite Dev Server Host/Port
Avoid binding to 0.0.0.0 by default—use localhost and fall back to env vars for multi-device testing:

// vite.config.ts
 server: {
-  host: '0.0.0.0',
-  port: 5173
+  host: process.env.VITE_DEV_HOST ?? 'localhost',
+  port: Number(process.env.VITE_DEV_PORT ?? 5173),
 }

• This lets you override via VITE_DEV_HOST/VITE_DEV_PORT when you need LAN access, without duplicating the --host CLI flag.
• Don’t forget to add your actual dev URL(s) (e.g. http://localhost:5173 or any LAN IP) to Firebase Authentication’s Authorized Domains.

🤖 Prompt for AI Agents
In vite.config.ts around lines 7 to 10, the dev server is hardcoded to host
'0.0.0.0' and port 5173; change it to use localhost by default and read fallback
values from VITE_DEV_HOST and VITE_DEV_PORT environment variables so developers
only opt into LAN binding when they set the envs. Update the server config to
set host = process.env.VITE_DEV_HOST || 'localhost' and port =
Number(process.env.VITE_DEV_PORT) || 5173 (ensure numeric conversion and a safe
default), and ensure any dev URLs you use are added to Firebase Auth Authorized
Domains when enabling LAN access.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

🚀 Feature: Add Google Login using Firebase Authentication

2 participants