Authentication Hooks
This document details the custom React hooks for authentication and authorization in the BuildAppsWith platform. These hooks encapsulate authentication state and business logic for use in React components.
The authentication system uses the Express SDK implementation internally. Most hooks are wrapper functions that forward to Express SDK implementations for consistent API access.
Core Authentication Hooks
useAuth
The useAuth hook provides access to the current authentication state and user information in client components. It forwards to the Express SDK implementation of auth state management.
import { useAuth } from '@/hooks/auth';
function UserProfile() {
const { user, isLoaded, isSignedIn, hasRole } = useAuth();
if (!isLoaded) return <LoadingSpinner />;
if (!isSignedIn) return <NotAuthenticated />;
return (
<div>
<h1>Welcome, {user.firstName}!</h1>
<p>Email: {user.email}</p>
<p>Is Admin: {hasRole(UserRole.ADMIN) ? 'Yes' : 'No'}</p>
</div>
);
}
Return Value
| Property | Type | Description |
|---|
user | User | null | Current user object or null if not authenticated |
isSignedIn | boolean | Whether the user is authenticated |
isLoaded | boolean | Whether the authentication state is loaded |
hasRole | (role: UserRole) => boolean | Function to check if user has a specific role |
roles | UserRole[] | Array of user roles |
userId | string | null | Current user ID or null |
useUser
The useUser hook provides access to user data, transforming it into an application-specific format.
import { useUser } from '@/hooks/auth';
function UserDetails() {
const { user, isLoaded } = useUser();
if (!isLoaded) return <LoadingSpinner />;
return (
<div>
<h2>{user.firstName} {user.lastName}</h2>
<p>Email: {user.email}</p>
<p>Created: {new Date(user.createdAt).toLocaleDateString()}</p>
</div>
);
}
Return Value
| Property | Type | Description |
|---|
user | User | null | User data in application format |
isLoaded | boolean | Whether user data is loaded |
Role-Based Authentication Hooks
useHasRole
Checks if the authenticated user has a specific role.
import { useHasRole, UserRole } from '@/hooks/auth';
function BuilderFeature() {
const isBuilder = useHasRole(UserRole.BUILDER);
if (!isBuilder) {
return <p>This feature is only available to builders.</p>;
}
return <BuilderTools />;
}
Parameters
| Parameter | Type | Description |
|---|
role | UserRole | The role to check for |
Return Value
| Type | Description |
|---|
boolean | Whether the user has the specified role |
useIsAdmin
Convenience hook for checking if the user has the admin role.
import { useIsAdmin } from '@/hooks/auth';
function AdminSection() {
const isAdmin = useIsAdmin();
if (!isAdmin) return null;
return <AdminPanel />;
}
Return Value
| Type | Description |
|---|
boolean | Whether the user has the admin role |
useIsBuilder
Convenience hook for checking if the user has the builder role.
import { useIsBuilder } from '@/hooks/auth';
function BuilderSection() {
const isBuilder = useIsBuilder();
if (!isBuilder) return null;
return <BuilderDashboard />;
}
Return Value
| Type | Description |
|---|
boolean | Whether the user has the builder role |
useIsClient
Convenience hook for checking if the user has the client role.
import { useIsClient } from '@/hooks/auth';
function ClientSection() {
const isClient = useIsClient();
if (!isClient) return null;
return <ClientDashboard />;
}
Return Value
| Type | Description |
|---|
boolean | Whether the user has the client role |
useHasAllRoles
Checks if the authenticated user has all of the specified roles.
import { useHasAllRoles, UserRole } from '@/hooks/auth';
function SuperUserSection() {
const isSuperUser = useHasAllRoles([UserRole.ADMIN, UserRole.BUILDER]);
if (!isSuperUser) return null;
return <SuperUserDashboard />;
}
Parameters
| Parameter | Type | Description |
|---|
roles | UserRole[] | Array of roles to check for |
Return Value
| Type | Description |
|---|
boolean | Whether the user has all of the specified roles |
useHasAnyRole
Checks if the authenticated user has any of the specified roles.
import { useHasAnyRole, UserRole } from '@/hooks/auth';
function SpecialSection() {
const hasAccess = useHasAnyRole([UserRole.ADMIN, UserRole.BUILDER]);
if (!hasAccess) return null;
return <SpecialContent />;
}
Parameters
| Parameter | Type | Description |
|---|
roles | UserRole[] | Array of roles to check for |
Return Value
| Type | Description |
|---|
boolean | Whether the user has any of the specified roles |
Authentication Status Hooks
useAuthStatus
Simple hook for checking authentication status.
import { useAuthStatus } from '@/hooks/auth';
function AuthStatusIndicator() {
const { isSignedIn, isLoaded } = useAuthStatus();
if (!isLoaded) {
return <LoadingDot />;
}
return (
<StatusIcon
color={isSignedIn ? 'green' : 'gray'}
tooltip={isSignedIn ? 'Signed In' : 'Not Signed In'}
/>
);
}
Return Value
| Property | Type | Description |
|---|
isSignedIn | boolean | Whether the user is authenticated |
isLoaded | boolean | Whether auth state is loaded |
useSignOut
Hook for accessing the sign-out functionality.
import { useSignOut } from '@/hooks/auth';
function SignOutButton() {
const signOut = useSignOut();
return (
<button
onClick={() => signOut()}
className="btn-secondary"
>
Sign Out
</button>
);
}
Return Value
| Type | Description |
|---|
() => Promise<void> | Function to sign the user out |
useAuthToken
Hook for accessing and refreshing auth tokens.
import { useAuthToken } from '@/hooks/auth';
function SecureApiCall() {
const { getToken, isLoading } = useAuthToken();
const makeApiCall = async () => {
if (isLoading) return;
const token = await getToken();
// Use the token for API call
const response = await fetch('/api/secure-data', {
headers: {
'Authorization': `Bearer ${token}`
}
});
// Handle response
};
return (
<button
onClick={makeApiCall}
disabled={isLoading}
>
Fetch Secure Data
</button>
);
}
Return Value
| Property | Type | Description |
|---|
getToken | () => Promise<string> | Function to get the current auth token |
refreshToken | () => Promise<string> | Function to refresh the auth token |
isLoading | boolean | Whether token operations are in progress |
Authorization Hooks
useHasPermission
The useHasPermission hook checks if the current user has a specific permission.
import { useHasPermission } from '@/lib/auth/hooks';
import { Permission } from '@/lib/auth/types';
function ModerateContent() {
const canModerate = useHasPermission(Permission.MODERATE_CONTENT);
if (!canModerate) {
return <p>You don't have permission to moderate content.</p>;
}
return (
<div>
<h1>Content Moderation</h1>
{/* Moderation UI */}
</div>
);
}
Parameters
| Parameter | Type | Description |
|---|
permission | Permission | Permission to check |
Return Value
| Type | Description |
|---|
boolean | Whether the user has the specified permission |
useRoles
The useRoles hook provides access to user roles and role checking.
import { useRoles } from '@/lib/auth/hooks';
import { UserRole } from '@/lib/auth/types';
function FeatureGating() {
const { roles, hasRole, isAdmin } = useRoles();
return (
<div>
<h1>Your Account</h1>
{hasRole(UserRole.BUILDER) && (
<BuilderDashboard />
)}
{isAdmin && (
<AdminControls />
)}
<p>Current roles: {roles.join(', ')}</p>
</div>
);
}
Return Value
| Property | Type | Description |
|---|
roles | UserRole[] | Array of user roles |
hasRole | (role: UserRole) => boolean | Function to check if user has a specific role |
isAdmin | boolean | Whether the user has admin role |
useSignIn
The useSignIn hook manages sign-in form state and submission.
import { useSignIn } from '@/lib/auth/hooks';
function SignInForm() {
const {
signIn,
isLoading,
error,
formState,
handleChange
} = useSignIn();
const handleSubmit = async (e) => {
e.preventDefault();
await signIn();
};
return (
<form onSubmit={handleSubmit}>
{error && <p className="text-red-500">{error}</p>}
<div>
<label htmlFor="email">Email</label>
<input
id="email"
name="email"
type="email"
value={formState.email}
onChange={handleChange}
required
/>
</div>
<div>
<label htmlFor="password">Password</label>
<input
id="password"
name="password"
type="password"
value={formState.password}
onChange={handleChange}
required
/>
</div>
<button type="submit" disabled={isLoading}>
{isLoading ? 'Signing in...' : 'Sign In'}
</button>
</form>
);
}
Return Value
| Property | Type | Description |
|---|
signIn | () => Promise<void> | Function to submit sign-in form |
isLoading | boolean | Whether sign-in is in progress |
error | string | null | Error message if sign-in failed |
formState | { email: string; password: string; } | Form state |
handleChange | (e: ChangeEvent<HTMLInputElement>) => void | Input change handler |
setFormState | Dispatch<SetStateAction<FormState>> | Form state setter |
useSignUp
The useSignUp hook manages sign-up form state and submission.
import { useSignUp } from '@/lib/auth/hooks';
function SignUpForm() {
const {
signUp,
isLoading,
error,
formState,
handleChange
} = useSignUp();
const handleSubmit = async (e) => {
e.preventDefault();
await signUp();
};
return (
<form onSubmit={handleSubmit}>
{error && <p className="text-red-500">{error}</p>}
<div>
<label htmlFor="email">Email</label>
<input
id="email"
name="email"
type="email"
value={formState.email}
onChange={handleChange}
required
/>
</div>
<div>
<label htmlFor="firstName">First Name</label>
<input
id="firstName"
name="firstName"
type="text"
value={formState.firstName}
onChange={handleChange}
required
/>
</div>
<div>
<label htmlFor="lastName">Last Name</label>
<input
id="lastName"
name="lastName"
type="text"
value={formState.lastName}
onChange={handleChange}
required
/>
</div>
<div>
<label htmlFor="password">Password</label>
<input
id="password"
name="password"
type="password"
value={formState.password}
onChange={handleChange}
required
/>
</div>
<button type="submit" disabled={isLoading}>
{isLoading ? 'Creating account...' : 'Create Account'}
</button>
</form>
);
}
Return Value
| Property | Type | Description |
|---|
signUp | () => Promise<void> | Function to submit sign-up form |
isLoading | boolean | Whether sign-up is in progress |
error | string | null | Error message if sign-up failed |
formState | { email: string; password: string; firstName: string; lastName: string; } | Form state |
handleChange | (e: ChangeEvent<HTMLInputElement>) => void | Input change handler |
setFormState | Dispatch<SetStateAction<FormState>> | Form state setter |
Higher-Order Component Pattern
withClientAuth
The withClientAuth HOC protects client-side components based on authentication status. It’s implemented using Express SDK hooks.
import { withClientAuth } from '@/hooks/auth';
import { UserRole } from '@/lib/auth/types';
// Component that requires authentication
function DashboardContent(props) {
return (
<div>
<h1>Dashboard</h1>
{/* Dashboard content */}
</div>
);
}
// Create protected component
const ProtectedDashboard = withClientAuth(DashboardContent, {
redirectTo: '/login?from=dashboard',
requiredRoles: [UserRole.USER],
requireAllRoles: false,
loadingComponent: <DashboardSkeleton />
});
// In a page component
export default function DashboardPage() {
return <ProtectedDashboard />;
}
Role-Based UI Elements
import { useAuth, useIsBuilder, useIsAdmin } from '@/hooks/auth';
function Navigation() {
const { isSignedIn } = useAuth();
const isBuilder = useIsBuilder();
const isAdmin = useIsAdmin();
return (
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/marketplace">Marketplace</a></li>
{isSignedIn && (
<li><a href="/dashboard">Dashboard</a></li>
)}
{isBuilder && (
<li><a href="/builder-profile">My Builder Profile</a></li>
)}
{isAdmin && (
<li><a href="/admin">Admin Panel</a></li>
)}
{isSignedIn ? (
<li><SignOutButton /></li>
) : (
<li><a href="/login">Sign In</a></li>
)}
</ul>
</nav>
);
}
Authentication Provider Integration
import { useAuth, useSignOut } from '@/hooks/auth';
function AuthStatus() {
const { isSignedIn, user, isLoaded } = useAuth();
const signOut = useSignOut();
if (!isLoaded) {
return <p>Loading authentication status...</p>;
}
if (isSignedIn) {
return (
<div>
<p>Signed in as {user.email}</p>
<button onClick={signOut}>Sign Out</button>
</div>
);
}
return (
<div>
<p>Not signed in</p>
<a href="/login">Sign In</a>
</div>
);
}
Express Auth Provider Integration
import { ExpressAuthProvider } from '@/components/auth/express-auth-provider';
function MyApp({ Component, pageProps }) {
return (
<ExpressAuthProvider>
<Component {...pageProps} />
</ExpressAuthProvider>
);
}
Best Practices
- Use specialized hooks for role checks - Prefer
useIsAdmin() over useHasRole(UserRole.ADMIN)
- Use
withClientAuth HOC for protected components - It handles all authentication/authorization concerns
- Leverage Express SDK hooks - They provide optimized performance and consistent API
- Use the
useAuthStatus hook for simple checks - When you only need isSignedIn/isLoaded status
- Separate auth state from business logic - Keep components focused on their primary responsibility
- Handle loading states properly - Always check isLoaded before using auth state
- Use specialized hooks for token access - Use
useAuthToken() for secure API calls
See Also