Overview
The Inmobiliaria Web application uses Better Auth for authentication. This guide covers the complete integration including client setup, authentication flows, and session management.
Installation
Install Better Auth
Install the Better Auth client package in your frontend project:
Configure Environment Variables
Set the backend API URL in your environment configuration: VITE_API_URL = http://localhost:10000/api
Client Initialization
The auth client is initialized in src/lib/auth-client.ts with the admin plugin enabled:
import { createAuthClient } from "better-auth/react" ;
import { adminClient } from "better-auth/client/plugins" ;
import { API_ORIGIN } from "./api" ;
export const authClient = createAuthClient ({
baseURL: API_ORIGIN ,
plugins: [ adminClient ()],
});
The API_ORIGIN is dynamically determined from the VITE_API_URL environment variable, defaulting to http://localhost:10000 for development.
Authentication Context
The application uses a React Context (AuthContext) to manage authentication state globally. Located in src/contexts/AuthContext.tsx, it provides:
User session state
Authentication methods (sign in, sign up, sign out)
Password reset functionality
Favorites management
Provider Setup
Wrap your application with the AuthProvider:
import { AuthProvider } from "./contexts/AuthContext" ;
function App () {
return (
< AuthProvider >
{ /* Your app components */ }
</ AuthProvider >
);
}
Using the Auth Hook
Access authentication state and methods using the useAuth hook:
import { useAuth } from "./contexts/AuthContext" ;
function MyComponent () {
const { user , loading , signIn , signOut } = useAuth ();
if ( loading ) return < div > Loading... </ div > ;
if ( ! user ) return < div > Not logged in </ div > ;
return (
< div >
< h1 > Welcome, { user . name } </ h1 >
< button onClick = { signOut } > Sign Out </ button >
</ div >
);
}
Authentication Flows
Sign Up
Create new user accounts with email verification:
const { signUp } = useAuth ();
const handleSignUp = async () => {
try {
await signUp ( email , password , name );
// User created - email verification required
alert ( "Check your email for verification!" );
} catch ( error ) {
console . error ( error . message );
}
};
Implementation
Full Example
const signUp = async ( email : string , password : string , name : string ) => {
const response = await authClient . signUp . email ({
email ,
password ,
name ,
callbackURL: "/" ,
});
if ( response . error ) {
throw response . error ;
}
};
Sign In
Authenticate existing users:
const { signIn } = useAuth ();
const handleSignIn = async () => {
try {
await signIn ( email , password );
// User signed in successfully
} catch ( error ) {
console . error ( error . message );
}
};
The signIn method automatically refreshes the session after successful authentication.
Google Social Sign In
Implement OAuth authentication with Google:
import { authClient } from "./lib/auth-client" ;
const handleGoogleSignIn = async () => {
await authClient . signIn . social ({
provider: "google" ,
callbackURL: "/dashboard" ,
});
};
Password Reset
Request Reset
User requests a password reset email: const { requestPasswordReset } = useAuth ();
const handleForgotPassword = async () => {
try {
await requestPasswordReset ( email );
alert ( "Reset email sent!" );
} catch ( error ) {
console . error ( error . message );
}
};
Reset Password
User submits new password with token from email: const { resetPassword } = useAuth ();
const handleResetPassword = async () => {
// Get token from URL query params
const token = searchParams . get ( "token" );
try {
await resetPassword ( token , newPassword );
alert ( "Password reset successfully!" );
navigate ( "/login" );
} catch ( error ) {
console . error ( error . message );
}
};
After a successful password reset, users must sign in again. The reset process does not automatically create a session.
Session Management
Automatic Session Refresh
The AuthContext automatically checks and refreshes the session on mount:
src/contexts/AuthContext.tsx
const refreshSession = async () => {
const { data } = await authClient . getSession ();
if ( data ?. user ) {
const user = data . user as unknown as User ;
// Fetch user favorites
const favoritesResponse = await api . users . getFavorites ();
const favoriteIds = favoritesResponse . data ?. map (
( property : Property ) => property . id
) || [];
setAuthState ({
user ,
loading: false ,
error: null ,
favoritePropertyIds: favoriteIds ,
refreshingSession: false ,
});
}
};
Using Session Data
Access the current user session:
const { user , loading } = useAuth ();
if ( loading ) {
return < LoadingSpinner /> ;
}
if ( ! user ) {
return < LoginPrompt /> ;
}
return (
< div >
< p > Email: { user . email } </ p >
< p > Name: { user . name } </ p >
< p > Role: { user . role } </ p >
</ div >
);
Protected Routes
Implement route protection based on authentication state:
import { useAuth } from "./contexts/AuthContext" ;
import { Navigate } from "@tanstack/react-router" ;
function ProtectedRoute ({ children }) {
const { user , loading } = useAuth ();
if ( loading ) {
return < LoadingSpinner /> ;
}
if ( ! user ) {
return < Navigate to = "/login" /> ;
}
return children ;
}
Error Handling
The application includes error translation utilities for user-friendly messages:
src/utils/authErrorTranslator.ts
export const translateAuthError = ( errorMessage : string ) : string => {
// Map English error messages to Spanish
if ( errorMessage . includes ( "Invalid credentials" )) {
return "Credenciales inválidas" ;
}
// ... more translations
return errorMessage ;
};
Errors are automatically handled in the AuthContext and cleared after 5 seconds:
const { error } = useAuth ();
{ error && (
< div className = "error-message" >
{ error }
</ div >
)}
Favorites Management
The auth context includes favorites management:
const { addToFavorites , removeFromFavorites , isFavorite } = useAuth ();
// Check if property is favorited
const isPropertyFavorited = isFavorite ( propertyId );
// Add to favorites
await addToFavorites ( propertyId );
// Remove from favorites
await removeFromFavorites ( propertyId );
Best Practices
Always check loading state before rendering user-dependent UI
Handle errors gracefully with user-friendly messages
Use the refreshSession method after operations that modify user state
Implement proper loading states during authentication operations
Clear sensitive data on sign out
API Reference
AuthContext Methods
Method Parameters Description signInemail, passwordSign in with email and password signUpemail, password, nameCreate new user account signOut- Sign out current user refreshSession- Manually refresh user session requestPasswordResetemailSend password reset email resetPasswordtoken, newPasswordReset password with token addToFavoritespropertyIdAdd property to favorites removeFromFavoritespropertyIdRemove property from favorites isFavoritepropertyIdCheck if property is favorited
Auth State
Property Type Description userUser | nullCurrent authenticated user loadingbooleanAuthentication operation in progress errorstring | nullCurrent error message favoritePropertyIdsstring[]Array of favorited property IDs