npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@frank-auth/react

v0.1.37

Published

Flexible and customizable React UI components for Frank Authentication

Readme

@frank-auth/react

A comprehensive, highly configurable React authentication UI library for the Frank Auth multi-tenant SaaS platform.

npm version License: MIT TypeScript

🌟 Features

  • 🎨 Highly Customizable: Server-driven configuration with complete theme control
  • 🏢 Multi-Tenant: Built-in organization management and switching
  • 👥 Three-Tier Users: Support for Internal, External, and End Users
  • 🔐 Advanced Security: MFA, Passkeys, OAuth, Magic Links
  • 🌍 Internationalization: 10+ languages with RTL support
  • ♿ Accessibility: WCAG 2.1 AA compliant
  • 📱 Responsive: Mobile-first design
  • ⚡ Performance: Tree-shaking, lazy loading, optimized bundles
  • 🎯 TypeScript: Full type safety and IntelliSense
  • 🔧 Framework Agnostic: Works with Next.js, Remix, Vite, and more

🚀 Quick Start

Installation

npm install @frank-auth/react
# or
yarn add @frank-auth/react
# or
pnpm add @frank-auth/react

Basic Setup

import { FrankAuthProvider, SignIn, UserButton } from '@frank-auth/react';

function App() {
  return (
    <FrankAuthProvider publishableKey="pk_test_...">
      <div className="app">
        <nav>
          <UserButton />
        </nav>
        <main>
          <SignIn />
        </main>
      </div>
    </FrankAuthProvider>
  );
}

Advanced Setup with Configuration

import { 
  FrankAuthProvider, 
  SignIn, 
  UserButton,
  createFrankAuthConfig 
} from '@frank-auth/react';

const config = createFrankAuthConfig({
  appearance: {
    theme: 'auto',
    colors: {
      primary: '#6366f1',
      background: '#ffffff',
      foreground: '#0f172a',
    },
    elements: {
      formButtonPrimary: 'bg-indigo-600 hover:bg-indigo-700',
      card: 'shadow-xl border-2 border-indigo-100',
    },
  },
  authentication: {
    methods: ['email', 'oauth', 'passkey'],
    mfa: {
      enabled: true,
      methods: ['totp', 'sms'],
    },
    oauth: {
      providers: [
        { provider: 'google', enabled: true },
        { provider: 'github', enabled: true },
      ],
    },
  },
  organization: {
    enabled: true,
    allowInvitations: true,
    maxMembers: 50,
  },
});

function App() {
  return (
    <FrankAuthProvider 
      publishableKey="pk_test_..."
      config={config}
      onAuthEvent={(event) => {
        console.log('Auth event:', event);
      }}
    >
      <SignIn mode="modal" />
      <UserButton showProfile showOrganization />
    </FrankAuthProvider>
  );
}

🎯 Component Examples

Authentication Components

SignIn Component

import { SignIn } from '@frank-auth/react';

// Basic usage
<SignIn />

// Modal mode
<SignIn mode="modal" />

// Custom appearance
<SignIn 
  appearance={{
    elements: {
      formButtonPrimary: 'bg-blue-600 hover:bg-blue-700',
      card: 'rounded-2xl shadow-2xl',
    }
  }}
/>

// With custom handlers
<SignIn 
  onSignInSuccess={(user) => {
    console.log('Welcome back!', user);
    // Custom redirect or action
  }}
  onSignInError={(error) => {
    console.error('Sign in failed:', error);
    // Custom error handling
  }}
/>

// Limited authentication methods
<SignIn 
  allowedMethods={['email', 'oauth']}
  redirectAfterSignIn="/dashboard"
/>

SignUp Component

import { SignUp } from '@frank-auth/react';

// Basic usage
<SignUp />

// With custom fields
<SignUp 
  customFields={[
    {
      id: 'company',
      name: 'Company Name',
      type: 'text',
      required: true,
    },
    {
      id: 'role',
      name: 'Role',
      type: 'select',
      options: [
        { value: 'developer', label: 'Developer' },
        { value: 'designer', label: 'Designer' },
        { value: 'manager', label: 'Manager' },
      ],
    },
  ]}
/>

UserButton Component

import { UserButton } from '@frank-auth/react';

// Basic usage
<UserButton />

// With custom actions
<UserButton 
  customActions={[
    {
      label: 'Settings',
      action: () => navigate('/settings'),
      icon: <SettingsIcon />,
    },
    {
      label: 'Billing',
      action: () => navigate('/billing'),
      icon: <CreditCardIcon />,
    },
  ]}
/>

// Show specific sections
<UserButton 
  showProfile={true}
  showOrganization={true}
  showSessions={true}
/>

Organization Components

Organization Switcher

import { OrganizationSwitcher } from '@frank-auth/react';

// Basic usage
<OrganizationSwitcher />

// With creation and switching
<OrganizationSwitcher 
  allowCreation={true}
  allowSwitching={true}
  showMembers={true}
/>

// Custom appearance
<OrganizationSwitcher 
  appearance={{
    elements: {
      organizationSwitcher: 'rounded-lg border-2',
    }
  }}
/>

Organization Profile

import { OrganizationProfile } from '@frank-auth/react';

// Full organization management
<OrganizationProfile 
  showMembers={true}
  showSettings={true}
  showBilling={true}
/>

🎨 Customization

Theme Configuration

const customTheme = {
  name: 'custom-theme',
  colors: {
    primary: '#8b5cf6',
    secondary: '#06b6d4',
    background: '#fafafa',
    foreground: '#18181b',
    muted: '#f4f4f5',
    accent: '#f59e0b',
    destructive: '#ef4444',
    border: '#e4e4e7',
    input: '#ffffff',
    ring: '#8b5cf6',
    success: '#10b981',
    warning: '#f59e0b',
    error: '#ef4444',
  },
  typography: {
    fontFamily: 'Inter, -apple-system, sans-serif',
    fontSize: {
      xs: '0.75rem',
      sm: '0.875rem',
      base: '1rem',
      lg: '1.125rem',
      xl: '1.25rem',
      '2xl': '1.5rem',
      '3xl': '1.875rem',
    },
  },
  layout: {
    borderRadius: '0.75rem',
    spacing: {
      xs: '0.25rem',
      sm: '0.5rem',
      md: '1rem',
      lg: '1.5rem',
      xl: '3rem',
    },
  },
};

<FrankAuthProvider 
  publishableKey="pk_test_..."
  config={{
    appearance: {
      theme: customTheme,
    }
  }}
>
  {/* Your app */}
</FrankAuthProvider>

Component Overrides

import { FrankAuthProvider } from '@frank-auth/react';
import { CustomSignIn, CustomUserButton } from './custom-components';

<FrankAuthProvider 
  publishableKey="pk_test_..."
  config={{
    components: {
      SignIn: CustomSignIn,
      UserButton: CustomUserButton,
    }
  }}
>
  {/* Your app */}
</FrankAuthProvider>

CSS-in-JS Customization

const config = {
  appearance: {
    elements: {
      // Form elements
      formButtonPrimary: 'bg-gradient-to-r from-purple-500 to-pink-500 hover:from-purple-600 hover:to-pink-600 text-white font-semibold py-2 px-4 rounded-lg shadow-lg transform transition hover:scale-105',
      formFieldInput: 'border-2 border-gray-200 focus:border-purple-500 rounded-lg px-3 py-2 transition-colors',
      formFieldLabel: 'text-sm font-medium text-gray-700 mb-1',
      
      // Cards
      card: 'bg-white/80 backdrop-blur-sm border border-gray-200 rounded-2xl shadow-xl',
      cardHeader: 'border-b border-gray-100 p-6',
      cardBody: 'p-6',
      
      // Modal
      modalOverlay: 'fixed inset-0 bg-black/50 backdrop-blur-sm',
      modalContent: 'bg-white rounded-2xl shadow-2xl max-w-md w-full mx-4',
      
      // User interface
      userButton: 'flex items-center space-x-2 px-3 py-2 rounded-lg hover:bg-gray-100 transition-colors',
      organizationSwitcher: 'border border-gray-200 rounded-lg p-2 hover:bg-gray-50',
    },
    variables: {
      '--frank-auth-primary': '#8b5cf6',
      '--frank-auth-radius': '0.75rem',
      '--frank-auth-shadow': '0 10px 25px -5px rgba(0, 0, 0, 0.1)',
    },
  },
};

🔧 Hooks Usage

useAuth Hook

import { useAuth } from '@frank-auth/react';

function MyComponent() {
  const { 
    isLoaded, 
    isSignedIn, 
    user, 
    signOut,
    organization,
    switchOrganization 
  } = useAuth();

  if (!isLoaded) {
    return <div>Loading...</div>;
  }

  if (!isSignedIn) {
    return <div>Please sign in</div>;
  }

  return (
    <div>
      <h1>Welcome, {user.firstName}!</h1>
      <p>Organization: {organization?.name}</p>
      <button onClick={() => signOut()}>
        Sign Out
      </button>
    </div>
  );
}

useOrganization Hook

import { useOrganization } from '@frank-auth/react';

function OrganizationDashboard() {
  const { 
    organization, 
    members, 
    invitations,
    isAdmin,
    inviteMember,
    removeMember 
  } = useOrganization();

  const handleInvite = async (email: string, role: string) => {
    try {
      await inviteMember({ email, role });
      toast.success('Invitation sent!');
    } catch (error) {
      toast.error('Failed to send invitation');
    }
  };

  return (
    <div>
      <h1>{organization.name}</h1>
      <p>{members.length} members</p>
      
      {isAdmin && (
        <button onClick={() => handleInvite('[email protected]', 'member')}>
          Invite Member
        </button>
      )}
    </div>
  );
}

usePermissions Hook

import { usePermissions } from '@frank-auth/react';

function AdminPanel() {
  const { hasPermission, hasRole, checkPermission } = usePermissions();

  const canManageUsers = hasPermission('users:write');
  const isAdmin = hasRole('admin');
  const canDeletePosts = checkPermission('posts:delete', { resourceId: 'post-123' });

  return (
    <div>
      {canManageUsers && (
        <button>Manage Users</button>
      )}
      
      {isAdmin && (
        <button>Admin Settings</button>
      )}
      
      {canDeletePosts && (
        <button>Delete Post</button>
      )}
    </div>
  );
}

🌐 Multi-Tenant Examples

Organization-Specific Branding

// This configuration is automatically loaded from your Frank Auth backend
// based on the current organization context

function App() {
  return (
    <FrankAuthProvider 
      publishableKey="pk_test_..."
      organizationId="org_acme_corp"
      onConfigLoad={(serverConfig) => {
        // Server config includes organization-specific branding
        console.log('Organization theme:', serverConfig.theme);
        console.log('Organization logo:', serverConfig.branding.logo);
      }}
    >
      <SignIn />
    </FrankAuthProvider>
  );
}

Dynamic User Type Handling

import { useAuth, configureForUserType } from '@frank-auth/react';

function AppWrapper() {
  const { user } = useAuth();
  
  // Configure based on user type
  const config = configureForUserType(user?.type || 'end-users', {
    appearance: {
      theme: user?.type === 'internal' ? 'dark' : 'light',
    },
  });

  return (
    <FrankAuthProvider 
      publishableKey="pk_test_..."
      config={config}
    >
      <App />
    </FrankAuthProvider>
  );
}

🔐 Advanced Security Features

Multi-Factor Authentication

import { useMfa } from '@frank-auth/react';

function SecuritySettings() {
  const { 
    mfaEnabled, 
    availableMethods, 
    enableMfa, 
    disableMfa,
    generateBackupCodes 
  } = useMfa();

  const handleEnableMfa = async (method: 'totp' | 'sms') => {
    try {
      const qrCode = await enableMfa(method);
      // Show QR code to user for TOTP setup
    } catch (error) {
      console.error('Failed to enable MFA:', error);
    }
  };

  return (
    <div>
      <h2>Two-Factor Authentication</h2>
      <p>Status: {mfaEnabled ? 'Enabled' : 'Disabled'}</p>
      
      {!mfaEnabled && (
        <div>
          <button onClick={() => handleEnableMfa('totp')}>
            Enable Authenticator App
          </button>
          <button onClick={() => handleEnableMfa('sms')}>
            Enable SMS
          </button>
        </div>
      )}
      
      {mfaEnabled && (
        <div>
          <button onClick={generateBackupCodes}>
            Generate Backup Codes
          </button>
          <button onClick={disableMfa}>
            Disable MFA
          </button>
        </div>
      )}
    </div>
  );
}

Passkey Integration

import { usePasskeys } from '@frank-auth/react';

function PasskeySettings() {
  const { 
    passkeys, 
    registerPasskey, 
    removePasskey,
    isSupported 
  } = usePasskeys();

  if (!isSupported) {
    return <div>Passkeys are not supported in this browser</div>;
  }

  const handleRegister = async () => {
    try {
      await registerPasskey({ name: 'My Device' });
      toast.success('Passkey registered successfully!');
    } catch (error) {
      toast.error('Failed to register passkey');
    }
  };

  return (
    <div>
      <h2>Passkeys</h2>
      <button onClick={handleRegister}>
        Add Passkey
      </button>
      
      <div className="mt-4">
        {passkeys.map((passkey) => (
          <div key={passkey.id} className="flex items-center justify-between p-3 border rounded">
            <div>
              <p className="font-medium">{passkey.name}</p>
              <p className="text-sm text-gray-500">
                Added {new Date(passkey.createdAt).toLocaleDateString()}
              </p>
            </div>
            <button 
              onClick={() => removePasskey(passkey.id)}
              className="text-red-600 hover:text-red-800"
            >
              Remove
            </button>
          </div>
        ))}
      </div>
    </div>
  );
}

🚀 Framework Integration

Next.js Integration

// pages/_app.tsx
import { FrankAuthProvider } from '@frank-auth/react';
import type { AppProps } from 'next/app';

export default function App({ Component, pageProps }: AppProps) {
  return (
    <FrankAuthProvider publishableKey={process.env.NEXT_PUBLIC_FRANK_AUTH_PUBLISHABLE_KEY!}>
      <Component {...pageProps} />
    </FrankAuthProvider>
  );
}

// pages/dashboard.tsx
import { RequireAuth } from '@frank-auth/react';

export default function Dashboard() {
  return (
    <RequireAuth>
      <div>
        <h1>Dashboard</h1>
        {/* Protected content */}
      </div>
    </RequireAuth>
  );
}

Remix Integration

// app/root.tsx
import { FrankAuthProvider } from '@frank-auth/react';

export default function App() {
  return (
    <html>
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width,initial-scale=1" />
      </head>
      <body>
        <FrankAuthProvider publishableKey={ENV.FRANK_AUTH_PUBLISHABLE_KEY}>
          <Outlet />
        </FrankAuthProvider>
      </body>
    </html>
  );
}

📱 Mobile and Responsive Design

All components are mobile-first and responsive by default:

// Components automatically adapt to screen size
<SignIn mode="card" /> // Becomes full-screen on mobile

// Custom responsive behavior
<UserButton 
  className="hidden md:block" // Hide on mobile
/>

<UserButton 
  className="md:hidden" // Show only on mobile
  showProfile={false} // Simplified mobile view
/>

🌍 Internationalization

import { FrankAuthProvider } from '@frank-auth/react';

const config = {
  localization: {
    defaultLocale: 'en',
    supportedLocales: ['en', 'es', 'fr', 'de', 'pt', 'it', 'ja', 'ko', 'zh'],
    customTranslations: {
      'es': {
        'sign_in': 'Iniciar Sesión',
        'sign_up': 'Registrarse',
        'welcome_back': 'Bienvenido de vuelta',
      },
    },
  },
};

<FrankAuthProvider 
  publishableKey="pk_test_..."
  config={config}
>
  {/* Components will use Spanish translations */}
</FrankAuthProvider>

🔧 Development and Debugging

Debug Mode

<FrankAuthProvider 
  publishableKey="pk_test_..."
  config={{
    advanced: {
      debug: true, // Enable debug logging
      telemetry: false, // Disable telemetry in development
    }
  }}
>
  <App />
</FrankAuthProvider>

Dev Tools

import { AuthDevTools } from '@frank-auth/react';

function App() {
  return (
    <div>
      {/* Your app */}
      {process.env.NODE_ENV === 'development' && <AuthDevTools />}
    </div>
  );
}

📚 API Reference

Configuration Options

| Option | Type | Description | |--------|------|-------------| | publishableKey | string | Your Frank Auth publishable key | | organizationId | string | Current organization ID | | appearance | AppearanceConfig | Theme and styling configuration | | authentication | AuthenticationConfig | Authentication methods and settings | | organization | OrganizationConfig | Organization features and settings | | localization | LocalizationConfig | Language and locale settings | | components | ComponentOverrides | Custom component overrides | | advanced | AdvancedConfig | Advanced options and debugging |

Component Props

All components accept these common props:

| Prop | Type | Description | |------|------|-------------| | className | string | Additional CSS classes | | appearance | Partial<AppearanceConfig> | Component-specific appearance | | onSuccess | (result: any) => void | Success callback | | onError | (error: Error) => void | Error callback |

🤝 Migration from ClerkJS

Frank Auth React is designed to be API-compatible with ClerkJS for easy migration:

// Before (ClerkJS)
import { ClerkProvider, SignIn, UserButton } from '@clerk/nextjs';

<ClerkProvider publishableKey="pk_test_...">
  <SignIn />
  <UserButton />
</ClerkProvider>

// After (Frank Auth)
import { FrankAuthProvider, SignIn, UserButton } from '@frank-auth/react';

<FrankAuthProvider publishableKey="pk_test_...">
  <SignIn />
  <UserButton />
</FrankAuthProvider>

📄 License

MIT License - see the LICENSE file for details.

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

📞 Support


Made with ❤️ by the Frank Auth team