From 603efd1b52a36b20cde5b261b34dd96f30e04014 Mon Sep 17 00:00:00 2001 From: Eric Lay Date: Wed, 11 Mar 2026 08:47:20 -0500 Subject: [PATCH] Add src/lib/AuthContext.jsx --- src/lib/AuthContext.jsx | 154 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 src/lib/AuthContext.jsx diff --git a/src/lib/AuthContext.jsx b/src/lib/AuthContext.jsx new file mode 100644 index 0000000..47f67d1 --- /dev/null +++ b/src/lib/AuthContext.jsx @@ -0,0 +1,154 @@ +import React, { createContext, useState, useContext, useEffect } from 'react'; +import { base44 } from '@/api/base44Client'; +import { appParams } from '@/lib/app-params'; +import { createAxiosClient } from '@base44/sdk/dist/utils/axios-client'; + +const AuthContext = createContext(); + +export const AuthProvider = ({ children }) => { + const [user, setUser] = useState(null); + const [isAuthenticated, setIsAuthenticated] = useState(false); + const [isLoadingAuth, setIsLoadingAuth] = useState(true); + const [isLoadingPublicSettings, setIsLoadingPublicSettings] = useState(true); + const [authError, setAuthError] = useState(null); + const [appPublicSettings, setAppPublicSettings] = useState(null); // Contains only { id, public_settings } + + useEffect(() => { + checkAppState(); + }, []); + + const checkAppState = async () => { + try { + setIsLoadingPublicSettings(true); + setAuthError(null); + + // First, check app public settings (with token if available) + // This will tell us if auth is required, user not registered, etc. + const appClient = createAxiosClient({ + baseURL: `/api/apps/public`, + headers: { + 'X-App-Id': appParams.appId + }, + token: appParams.token, // Include token if available + interceptResponses: true + }); + + try { + const publicSettings = await appClient.get(`/prod/public-settings/by-id/${appParams.appId}`); + setAppPublicSettings(publicSettings); + + // If we got the app public settings successfully, check if user is authenticated + if (appParams.token) { + await checkUserAuth(); + } else { + setIsLoadingAuth(false); + setIsAuthenticated(false); + } + setIsLoadingPublicSettings(false); + } catch (appError) { + console.error('App state check failed:', appError); + + // Handle app-level errors + if (appError.status === 403 && appError.data?.extra_data?.reason) { + const reason = appError.data.extra_data.reason; + if (reason === 'auth_required') { + setAuthError({ + type: 'auth_required', + message: 'Authentication required' + }); + } else if (reason === 'user_not_registered') { + setAuthError({ + type: 'user_not_registered', + message: 'User not registered for this app' + }); + } else { + setAuthError({ + type: reason, + message: appError.message + }); + } + } else { + setAuthError({ + type: 'unknown', + message: appError.message || 'Failed to load app' + }); + } + setIsLoadingPublicSettings(false); + setIsLoadingAuth(false); + } + } catch (error) { + console.error('Unexpected error:', error); + setAuthError({ + type: 'unknown', + message: error.message || 'An unexpected error occurred' + }); + setIsLoadingPublicSettings(false); + setIsLoadingAuth(false); + } + }; + + const checkUserAuth = async () => { + try { + // Now check if the user is authenticated + setIsLoadingAuth(true); + const currentUser = await base44.auth.me(); + setUser(currentUser); + setIsAuthenticated(true); + setIsLoadingAuth(false); + } catch (error) { + console.error('User auth check failed:', error); + setIsLoadingAuth(false); + setIsAuthenticated(false); + + // If user auth fails, it might be an expired token + if (error.status === 401 || error.status === 403) { + setAuthError({ + type: 'auth_required', + message: 'Authentication required' + }); + } + } + }; + + const logout = (shouldRedirect = true) => { + setUser(null); + setIsAuthenticated(false); + + if (shouldRedirect) { + // Use the SDK's logout method which handles token cleanup and redirect + base44.auth.logout(window.location.href); + } else { + // Just remove the token without redirect + base44.auth.logout(); + } + }; + + const navigateToLogin = () => { + // Use the SDK's redirectToLogin method + base44.auth.redirectToLogin(window.location.href); + }; + + return ( + + {children} + + ); +}; + +export const useAuth = () => { + const context = useContext(AuthContext); + if (!context) { + throw new Error('useAuth must be used within an AuthProvider'); + } + return context; +};