From f5fa0863564c5238cc7a076c46a6fdde4ffe0dd4 Mon Sep 17 00:00:00 2001 From: Hanzo_dev <2002samudiojohan@gmail.com> Date: Mon, 23 Feb 2026 19:31:47 -0500 Subject: [PATCH] fix: Google Sign-In - Firebase Admin credentials via env var + mobile redirect flow --- backend/app/api/auth/__init__.py | 22 ++++++++++-- frontend/src/firebaseConfig.ts | 57 ++++++++++++++++++++++++++------ frontend/src/views/AuthView.vue | 28 +++++++++++++++- render.yaml | 4 +++ 4 files changed, 96 insertions(+), 15 deletions(-) diff --git a/backend/app/api/auth/__init__.py b/backend/app/api/auth/__init__.py index f3f74eb..1e5b0ba 100644 --- a/backend/app/api/auth/__init__.py +++ b/backend/app/api/auth/__init__.py @@ -1,4 +1,5 @@ import os +import json import shutil from uuid import uuid4 from typing import Annotated, Optional @@ -12,11 +13,26 @@ from app.schemas.user import PassengerCreate, Token, UserResponse, LoginRequest, import firebase_admin from firebase_admin import auth as firebase_auth, credentials -# Initialize Firebase Admin +# Initialize Firebase Admin SDK +# Supports two methods: +# 1. FIREBASE_SERVICE_ACCOUNT_JSON env var with the full JSON as a string (recommended for Render/production) +# 2. GOOGLE_APPLICATION_CREDENTIALS env var pointing to a JSON file path (local dev) try: if not firebase_admin._apps: - # Default initialization (uses GOOGLE_APPLICATION_CREDENTIALS) - firebase_admin.initialize_app() + sa_json = os.environ.get("FIREBASE_SERVICE_ACCOUNT_JSON") + if sa_json: + # Parse the JSON string directly from environment variable + sa_dict = json.loads(sa_json) + cred = credentials.Certificate(sa_dict) + firebase_admin.initialize_app(cred) + print("DEBUG: Firebase Admin initialized from FIREBASE_SERVICE_ACCOUNT_JSON env var") + elif os.environ.get("GOOGLE_APPLICATION_CREDENTIALS"): + # Use file path from GOOGLE_APPLICATION_CREDENTIALS + firebase_admin.initialize_app() + print("DEBUG: Firebase Admin initialized from GOOGLE_APPLICATION_CREDENTIALS file") + else: + print("WARNING: No Firebase credentials found. Set FIREBASE_SERVICE_ACCOUNT_JSON or GOOGLE_APPLICATION_CREDENTIALS.") + firebase_admin.initialize_app() except Exception as e: print(f"WARNING: Firebase Admin could not be initialized: {e}") diff --git a/frontend/src/firebaseConfig.ts b/frontend/src/firebaseConfig.ts index cfc85ac..6d48c7e 100644 --- a/frontend/src/firebaseConfig.ts +++ b/frontend/src/firebaseConfig.ts @@ -1,5 +1,11 @@ import { initializeApp } from 'firebase/app'; -import { getAuth, GoogleAuthProvider, signInWithPopup } from 'firebase/auth'; +import { + getAuth, + GoogleAuthProvider, + signInWithPopup, + signInWithRedirect, + getRedirectResult +} from 'firebase/auth'; const firebaseConfig = { apiKey: "AIzaSyAG8nmGLHYmXGkl018NjW2sMcIiutM4ne0", @@ -14,17 +20,46 @@ const app = initializeApp(firebaseConfig); export const auth = getAuth(app); export const googleProvider = new GoogleAuthProvider(); -export const signInWithGoogle = async () => { - try { +// Detect if the user is on a mobile device +const isMobile = () => { + return /Android|iPhone|iPad|iPod|Opera Mini|IEMobile|WPDesktop/i.test(navigator.userAgent); +}; + +/** + * Signs in with Google. + * - Uses signInWithPopup on desktop (fast, no page reload) + * - Uses signInWithRedirect on mobile (avoids popup blocking on mobile browsers) + */ +export const signInWithGoogle = async (): Promise<{ user: any; token: string }> => { + if (isMobile()) { + // On mobile, redirect flow is more reliable + await signInWithRedirect(auth, googleProvider); + // The page will reload; the result is handled by getGoogleRedirectResult() on app load + // We return a never-resolving promise to keep the UI in loading state + return new Promise(() => { }); + } else { + // On desktop, use popup const result = await signInWithPopup(auth, googleProvider); - // This gives you a Google Access Token. You can use it to access the Google API. const token = await result.user.getIdToken(); - return { - user: result.user, - token: token - }; - } catch (error) { - console.error("Error signing in with Google", error); - throw error; + return { user: result.user, token }; + } +}; + +/** + * Call this once when the app loads (e.g., in App.vue or main.ts) to + * handle the result from a Google redirect login on mobile. + * Returns null if there is no pending redirect result. + */ +export const getGoogleRedirectResult = async (): Promise<{ user: any; token: string } | null> => { + try { + const result = await getRedirectResult(auth); + if (result && result.user) { + const token = await result.user.getIdToken(); + return { user: result.user, token }; + } + return null; + } catch (error) { + console.error("Error getting redirect result:", error); + return null; } }; diff --git a/frontend/src/views/AuthView.vue b/frontend/src/views/AuthView.vue index a97ce8c..54d0de0 100644 --- a/frontend/src/views/AuthView.vue +++ b/frontend/src/views/AuthView.vue @@ -1,10 +1,36 @@