"use client"; import React, { createContext, useContext, useState, useEffect, useCallback, ReactNode, } from "react"; interface User { user_id: string; email: string; name: string; picture?: string; provider: string; last_login?: string; } interface AuthContextType { user: User | null; isLoading: boolean; isAuthenticated: boolean; isNoAuthMode: boolean; login: () => void; logout: () => Promise; refreshAuth: () => Promise; } const AuthContext = createContext(undefined); export function useAuth() { const context = useContext(AuthContext); if (context === undefined) { throw new Error("useAuth must be used within an AuthProvider"); } return context; } interface AuthProviderProps { children: ReactNode; } export function AuthProvider({ children }: AuthProviderProps) { const [user, setUser] = useState(null); const [isLoading, setIsLoading] = useState(true); const [isNoAuthMode, setIsNoAuthMode] = useState(false); const checkAuth = useCallback(async () => { try { const response = await fetch("/api/auth/me"); // If we can't reach the backend, keep loading if (!response.ok && (response.status === 0 || response.status >= 500)) { console.log("Backend not ready, retrying in 2 seconds..."); setTimeout(checkAuth, 2000); return; } const data = await response.json(); // Check if we're in no-auth mode if (data.no_auth_mode) { setIsNoAuthMode(true); setUser(null); } else if (data.authenticated && data.user) { setIsNoAuthMode(false); setUser(data.user); } else { setIsNoAuthMode(false); setUser(null); } setIsLoading(false); } catch (error) { console.error("Auth check failed:", error); // Network error - backend not ready, keep loading and retry console.log("Backend not ready, retrying in 2 seconds..."); setTimeout(checkAuth, 2000); } }, []); const login = () => { // Don't allow login in no-auth mode if (isNoAuthMode) { console.log("Login attempted in no-auth mode - ignored"); return; } // Use the correct auth callback URL, not connectors callback const redirectUri = `${window.location.origin}/auth/callback`; console.log("Starting login with redirect URI:", redirectUri); fetch("/api/auth/init", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ connector_type: "google_drive", purpose: "app_auth", name: "App Authentication", redirect_uri: redirectUri, }), }) .then((response) => response.json()) .then((result) => { console.log("Auth init response:", result); if (result.oauth_config) { // Store that this is for app authentication localStorage.setItem("auth_purpose", "app_auth"); localStorage.setItem("connecting_connector_id", result.connection_id); localStorage.setItem("connecting_connector_type", "app_auth"); console.log("Stored localStorage items:", { auth_purpose: localStorage.getItem("auth_purpose"), connecting_connector_id: localStorage.getItem( "connecting_connector_id", ), connecting_connector_type: localStorage.getItem( "connecting_connector_type", ), }); const authUrl = `${result.oauth_config.authorization_endpoint}?` + `client_id=${result.oauth_config.client_id}&` + `response_type=code&` + `scope=${result.oauth_config.scopes.join(" ")}&` + `redirect_uri=${encodeURIComponent(result.oauth_config.redirect_uri)}&` + `access_type=offline&` + `prompt=consent&` + `state=${result.connection_id}`; console.log("Redirecting to OAuth URL:", authUrl); window.location.href = authUrl; } else { console.error("No oauth_config in response:", result); } }) .catch((error) => { console.error("Login failed:", error); }); }; const logout = async () => { // Don't allow logout in no-auth mode if (isNoAuthMode) { console.log("Logout attempted in no-auth mode - ignored"); return; } try { await fetch("/api/auth/logout", { method: "POST", }); setUser(null); } catch (error) { console.error("Logout failed:", error); } }; const refreshAuth = async () => { await checkAuth(); }; useEffect(() => { checkAuth(); }, [checkAuth]); const value: AuthContextType = { user, isLoading, isAuthenticated: !!user, isNoAuthMode, login, logout, refreshAuth, }; return {children}; }