Skip to main content

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

PropertyTypeDescription
userUser | nullCurrent user object or null if not authenticated
isSignedInbooleanWhether the user is authenticated
isLoadedbooleanWhether the authentication state is loaded
hasRole(role: UserRole) => booleanFunction to check if user has a specific role
rolesUserRole[]Array of user roles
userIdstring | nullCurrent 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

PropertyTypeDescription
userUser | nullUser data in application format
isLoadedbooleanWhether 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
ParameterTypeDescription
roleUserRoleThe role to check for
Return Value
TypeDescription
booleanWhether 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
TypeDescription
booleanWhether 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
TypeDescription
booleanWhether 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
TypeDescription
booleanWhether 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
ParameterTypeDescription
rolesUserRole[]Array of roles to check for
Return Value
TypeDescription
booleanWhether 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
ParameterTypeDescription
rolesUserRole[]Array of roles to check for
Return Value
TypeDescription
booleanWhether 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
PropertyTypeDescription
isSignedInbooleanWhether the user is authenticated
isLoadedbooleanWhether 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
TypeDescription
() => 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
PropertyTypeDescription
getToken() => Promise<string>Function to get the current auth token
refreshToken() => Promise<string>Function to refresh the auth token
isLoadingbooleanWhether 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

ParameterTypeDescription
permissionPermissionPermission to check

Return Value

TypeDescription
booleanWhether 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

PropertyTypeDescription
rolesUserRole[]Array of user roles
hasRole(role: UserRole) => booleanFunction to check if user has a specific role
isAdminbooleanWhether the user has admin role

Authentication Form Hooks

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

PropertyTypeDescription
signIn() => Promise<void>Function to submit sign-in form
isLoadingbooleanWhether sign-in is in progress
errorstring | nullError message if sign-in failed
formState{ email: string; password: string; }Form state
handleChange(e: ChangeEvent<HTMLInputElement>) => voidInput change handler
setFormStateDispatch<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

PropertyTypeDescription
signUp() => Promise<void>Function to submit sign-up form
isLoadingbooleanWhether sign-up is in progress
errorstring | nullError message if sign-up failed
formState{ email: string; password: string; firstName: string; lastName: string; }Form state
handleChange(e: ChangeEvent<HTMLInputElement>) => voidInput change handler
setFormStateDispatch<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

  1. Use specialized hooks for role checks - Prefer useIsAdmin() over useHasRole(UserRole.ADMIN)
  2. Use withClientAuth HOC for protected components - It handles all authentication/authorization concerns
  3. Leverage Express SDK hooks - They provide optimized performance and consistent API
  4. Use the useAuthStatus hook for simple checks - When you only need isSignedIn/isLoaded status
  5. Separate auth state from business logic - Keep components focused on their primary responsibility
  6. Handle loading states properly - Always check isLoaded before using auth state
  7. Use specialized hooks for token access - Use useAuthToken() for secure API calls

See Also