Skip to content

Client SDK Components

Pre-built React components for authentication flows.

Protected Routes

Using ProtectedRoute Component

import { ProtectedRoute } from '@authvital/sdk/client';
import { BrowserRouter, Routes, Route } from 'react-router-dom';

function App() {
  return (
    <AuthVitalProvider {...config}>
      <BrowserRouter>
        <Routes>
          {/* Public routes */}
          <Route path="/" element={<Home />} />
          <Route path="/pricing" element={<Pricing />} />

          {/* Protected routes */}
          <Route 
            path="/dashboard" 
            element={
              <ProtectedRoute>
                <Dashboard />
              </ProtectedRoute>
            } 
          />

          {/* Role-protected route */}
          <Route 
            path="/admin" 
            element={
              <ProtectedRoute requiredRoles={['admin', 'owner']}>
                <AdminPanel />
              </ProtectedRoute>
            } 
          />

          {/* Permission-protected route */}
          <Route 
            path="/users" 
            element={
              <ProtectedRoute requiredPermissions={['users:read']}>
                <UserList />
              </ProtectedRoute>
            } 
          />
        </Routes>
      </BrowserRouter>
    </AuthVitalProvider>
  );
}

ProtectedRoute Props

Prop Type Description
children ReactNode Content to render when authorized
requiredRoles string[] Roles required (ANY match)
requiredPermissions string[] Permissions required (ALL match)
fallback ReactNode Custom loading component
unauthorizedComponent ReactNode Shown when access denied

Custom Protected Route

import { useAuth } from '@authvital/sdk/client';
import { Navigate, useLocation } from 'react-router-dom';

function RequireAuth({ children }: { children: React.ReactNode }) {
  const { isAuthenticated, isLoading, login } = useAuth();
  const location = useLocation();

  if (isLoading) {
    return <LoadingSpinner />;
  }

  if (!isAuthenticated) {
    // Save location for redirect after login
    sessionStorage.setItem('redirectAfterLogin', location.pathname);
    return <Navigate to="/login" state={{ from: location }} replace />;
  }

  return <>{children}</>;
}

Permission & Role Checks

Direct Permission Check

import { useAuth } from '@authvital/sdk/client';

function AdminFeature() {
  const { user, currentTenant } = useAuth();

  // Check tenant role
  const isAdmin = currentTenant?.role === 'admin' || currentTenant?.role === 'owner';

  if (!isAdmin) {
    return <p>You don't have permission to access this feature.</p>;
  }

  return <UserManagementPanel />;
}

HasRole Component

function HasRole({ 
  role, 
  children,
  fallback = null,
}: { 
  role: string | string[];
  children: React.ReactNode;
  fallback?: React.ReactNode;
}) {
  const { currentTenant } = useAuth();

  const roles = Array.isArray(role) ? role : [role];
  const hasRole = currentTenant && roles.includes(currentTenant.role);

  if (!hasRole) return <>{fallback}</>;
  return <>{children}</>;
}

// Usage
<HasRole role={['admin', 'owner']} fallback={<DisabledButton />}>
  <DeleteUserButton />
</HasRole>

License & Feature Checks

Note

License information should be checked server-side and passed to the client via the user object. The client SDK doesn't have direct access to license data.

Check License Type

function PremiumFeature() {
  const { user } = useAuth();

  // Assuming your server includes license info in the user object
  const isPro = user?.license?.type === 'pro' || user?.license?.type === 'enterprise';

  if (!isPro) {
    return (
      <div className="upgrade-prompt">
        <p>This feature requires Pro or Enterprise.</p>
        <a href="/pricing">Upgrade Now</a>
      </div>
    );
  }

  return <AdvancedAnalytics />;
}

FeatureGate Component

function FeatureGate({ 
  feature, 
  children,
  fallback,
}: { 
  feature: string;
  children: React.ReactNode;
  fallback?: React.ReactNode;
}) {
  const { user } = useAuth();
  const hasFeature = user?.license?.features?.includes(feature);

  if (!hasFeature) {
    return fallback || (
      <div className="feature-locked">
        <p>Upgrade to unlock {feature}</p>
        <a href="/pricing">View Plans</a>
      </div>
    );
  }

  return <>{children}</>;
}

// Usage
<FeatureGate feature="advanced-reports">
  <ReportBuilder />
</FeatureGate>

Pre-Built Form Components

SignUpForm

import { SignUpForm } from '@authvital/sdk/client';

function SignUpPage() {
  return (
    <SignUpForm 
      onSuccess={(user) => {
        console.log('Signed up:', user);
        navigate('/dashboard');
      }}
      onError={(error) => {
        console.error('Signup failed:', error);
      }}
      fields={['email', 'password', 'givenName', 'familyName']}
    />
  );
}

CompleteSignupForm

For completing signup after invitation:

import { CompleteSignupForm } from '@authvital/sdk/client';

function CompleteSignupPage() {
  const { token } = useParams(); // Invitation token from URL

  return (
    <CompleteSignupForm 
      invitationToken={token}
      onSuccess={(user) => {
        navigate('/dashboard');
      }}
    />
  );
}

VerifyEmail

import { VerifyEmail } from '@authvital/sdk/client';

function VerifyEmailPage() {
  const { token } = useParams();

  return (
    <VerifyEmail 
      token={token}
      onSuccess={() => navigate('/dashboard')}
      onError={(error) => console.error(error)}
    />
  );
}

Error Handling

function Dashboard() {
  const { error, isAuthenticated, clearAuthState } = useAuth();

  if (error) {
    return (
      <div className="error">
        <h2>Authentication Error</h2>
        <p>{error}</p>
        <button onClick={() => {
          clearAuthState();
          window.location.href = '/login';
        }}>
          Try Again
        </button>
      </div>
    );
  }

  // ...
}