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 @@
diff --git a/render.yaml b/render.yaml
index 79306dd..d9314e9 100644
--- a/render.yaml
+++ b/render.yaml
@@ -18,6 +18,10 @@ services:
value: "false"
- key: PYTHON_VERSION
value: 3.13.0
+ # Firebase Admin SDK credentials (JSON string of service account)
+ # Set this manually in the Render dashboard — do NOT commit the actual value
+ - key: FIREBASE_SERVICE_ACCOUNT_JSON
+ sync: false
databases:
- name: sibu-db