BigBlocks Docs
Components/React Hooks

useBitcoinAuth

Core authentication hook for Bitcoin-based identity management

The primary hook for accessing Bitcoin authentication state, user data, and auth operations in BigBlocks applications. Provides comprehensive authentication management with Bitcoin-based identity where Bitcoin keypairs ARE the identity - no traditional usernames, emails, or passwords.

Usage

import { useBitcoinAuth } from 'bigblocks';

function MyComponent() {
  const {
    user,
    isAuthenticated,
    isLoading,
    error,
    signIn,
    signOut,
    hasWalletCapabilities,
    balance
  } = useBitcoinAuth();
  
  if (isLoading) {
    return <div>Loading...</div>;
  }
  
  if (!isAuthenticated) {
    return (
      <button onClick={() => signIn()}>
        Sign in with Bitcoin
      </button>
    );
  }
  
  return (
    <div>
      <h2>Welcome, {user.name}!</h2>
      <p>BAP ID: {user.bapId}</p>
      {hasWalletCapabilities && (
        <p>Balance: {balance} BSV</p>
      )}
      <button onClick={() => signOut()}>
        Sign out
      </button>
    </div>
  );
}

Return Value

interface UseBitcoinAuthReturn {
  // Authentication State
  user: AuthUser | null;                 // Current authenticated user
  isAuthenticated: boolean;              // Authentication status
  isLoading: boolean;                    // Loading state
  error: AuthError | null;               // Error state
  
  // Wallet Capabilities
  hasWalletCapabilities: boolean;        // Can make transactions
  balance: number | null;                // BSV balance
  address: string | null;                // Bitcoin address
  
  // Auth Operations
  signIn: (method?: AuthMethod) => Promise<void>;
  signOut: () => Promise<void>;
  refresh: () => Promise<void>;
  
  // Profile Management
  updateProfile: (data: ProfileUpdate) => Promise<void>;
  createProfile: (data: NewProfile) => Promise<void>;
  switchProfile: (bapId: string) => Promise<void>;
  
  // Backup Operations
  downloadBackup: () => Promise<void>;
  importBackup: (backup: string) => Promise<void>;
  linkOAuthProvider: (provider: OAuthProvider) => Promise<void>;
}

interface AuthUser {
  bapId: string;                         // BAP identity ID
  name: string;                          // Display name
  email?: string;                        // Email address
  avatar?: string;                       // Profile image URL
  publicKey: string;                     // Bitcoin public key
  address: string;                       // Bitcoin address
  createdAt: string;                     // Account creation date
  lastSeen: string;                      // Last activity
  verified: boolean;                     // Verification status
  reputation?: number;                   // Reputation score
  profiles: BapProfile[];                // Available profiles
}

Authentication Methods

Basic Bitcoin Authentication

The default authentication method uses Bitcoin signatures for cryptographic proof of identity:

function BasicAuth() {
  const { signIn, signOut, isAuthenticated, user } = useBitcoinAuth();
  
  const handleSignIn = async () => {
    try {
      await signIn('credentials'); // Default Bitcoin signature auth
      toast.success('Signed in successfully!');
    } catch (error) {
      toast.error('Sign in failed: ' + error.message);
    }
  };
  
  return (
    <div className="auth-section">
      {isAuthenticated ? (
        <div className="user-info">
          <h3>Welcome {user.name}!</h3>
          <p>Address: {user.address}</p>
          <button onClick={signOut}>Sign Out</button>
        </div>
      ) : (
        <button onClick={handleSignIn}>
          Sign In with Bitcoin
        </button>
      )}
    </div>
  );
}

OAuth Restoration

OAuth providers (Google, GitHub) serve as "anchors" to store encrypted backups, enabling cross-device access:

function OAuthRestore() {
  const { signIn, isLoading, error } = useBitcoinAuth();
  
  const handleOAuthRestore = async (provider) => {
    try {
      await signIn('oauth', { provider });
      // Will trigger OAuth flow and restore from cloud backup
    } catch (error) {
      console.error('OAuth restore failed:', error);
    }
  };
  
  return (
    <div className="oauth-restore">
      <h3>Restore from Cloud Backup</h3>
      
      <button 
        onClick={() => handleOAuthRestore('google')}
        disabled={isLoading}
      >
        {isLoading ? 'Restoring...' : 'Restore from Google'}
      </button>
      
      <button 
        onClick={() => handleOAuthRestore('github')}
        disabled={isLoading}
      >
        {isLoading ? 'Restoring...' : 'Restore from GitHub'}
      </button>
      
      {error && (
        <ErrorDisplay error={error.message} />
      )}
    </div>
  );
}

Profile Management

Multiple Profiles

Users can create and switch between multiple profiles within the same identity:

function ProfileSwitcher() {
  const {
    user,
    switchProfile,
    createProfile,
    updateProfile
  } = useBitcoinAuth();
  
  const [isCreating, setIsCreating] = useState(false);
  const [newProfileName, setNewProfileName] = useState('');
  
  const handleCreateProfile = async () => {
    if (!newProfileName.trim()) return;
    
    setIsCreating(true);
    try {
      await createProfile({
        name: newProfileName,
        bio: '',
        avatar: ''
      });
      setNewProfileName('');
      toast.success('Profile created successfully!');
    } catch (error) {
      toast.error('Failed to create profile');
    } finally {
      setIsCreating(false);
    }
  };
  
  return (
    <div className="profile-manager">
      <h3>Current Profile: {user.name}</h3>
      
      <div className="profile-list">
        {user.profiles.map(profile => (
          <div key={profile.bapId} className="profile-item">
            <BitcoinAvatar 
              src={profile.avatar}
              name={profile.name}
              size="small"
            />
            <span>{profile.name}</span>
            <button onClick={() => switchProfile(profile.bapId)}>
              Switch
            </button>
          </div>
        ))}
      </div>
      
      <div className="create-profile">
        <input 
          type="text"
          placeholder="New profile name"
          value={newProfileName}
          onChange={(e) => setNewProfileName(e.target.value)}
        />
        <button 
          onClick={handleCreateProfile}
          disabled={isCreating || !newProfileName.trim()}
        >
          {isCreating ? 'Creating...' : 'Create Profile'}
        </button>
      </div>
    </div>
  );
}

Wallet Integration

Balance and Transaction Capabilities

The hook provides wallet functionality when the user has imported a wallet-enabled backup:

function WalletBalance() {
  const { hasWalletCapabilities, balance, address, refresh } = useBitcoinAuth();
  const [refreshing, setRefreshing] = useState(false);
  
  const handleRefresh = async () => {
    setRefreshing(true);
    try {
      await refresh();
    } finally {
      setRefreshing(false);
    }
  };
  
  if (!hasWalletCapabilities) {
    return (
      <div className="wallet-unavailable">
        <p>Wallet features not available</p>
        <p>Sign in with a wallet-enabled backup</p>
      </div>
    );
  }
  
  return (
    <div className="wallet-info">
      <div className="balance-section">
        <h4>Wallet Balance</h4>
        <SimpleTokenBalance 
          symbol="BSV"
          balance={balance || 0}
          showSymbol={true}
        />
        <button 
          onClick={handleRefresh}
          disabled={refreshing}
          className="refresh-button"
        >
          {refreshing ? '🔄' : '↻'} Refresh
        </button>
      </div>
      
      <div className="address-section">
        <h4>Bitcoin Address</h4>
        <div className="address-display">
          <code>{address}</code>
          <button onClick={() => navigator.clipboard.writeText(address)}>
            Copy
          </button>
        </div>
      </div>
    </div>
  );
}

Backup Management

Download and Cloud Backup

Secure backup management with local download and OAuth provider linking:

function BackupManager() {
  const { downloadBackup, linkOAuthProvider } = useBitcoinAuth();
  const [downloading, setDownloading] = useState(false);
  const [linking, setLinking] = useState(false);
  
  const handleDownloadBackup = async () => {
    setDownloading(true);
    try {
      await downloadBackup();
      toast.success('Backup downloaded successfully!');
    } catch (error) {
      toast.error('Backup download failed');
    } finally {
      setDownloading(false);
    }
  };
  
  const handleLinkProvider = async (provider) => {
    setLinking(true);
    try {
      await linkOAuthProvider(provider);
      toast.success(`${provider} linked successfully!`);
    } catch (error) {
      toast.error(`Failed to link ${provider}`);
    } finally {
      setLinking(false);
    }
  };
  
  return (
    <div className="backup-manager">
      <h3>Backup & Security</h3>
      
      <div className="backup-section">
        <h4>Local Backup</h4>
        <p>Download an encrypted backup file</p>
        <LoadingButton 
          onClick={handleDownloadBackup}
          loading={downloading}
        >
          Download Backup
        </LoadingButton>
      </div>
      
      <div className="cloud-backup-section">
        <h4>Cloud Backup</h4>
        <p>Link OAuth providers for cloud backup access</p>
        
        <div className="provider-buttons">
          <LoadingButton 
            onClick={() => handleLinkProvider('google')}
            loading={linking}
            variant="outline"
          >
            Link Google
          </LoadingButton>
          
          <LoadingButton 
            onClick={() => handleLinkProvider('github')}
            loading={linking}
            variant="outline"
          >
            Link GitHub
          </LoadingButton>
        </div>
      </div>
    </div>
  );
}

Error Handling

Authentication Error Recovery

Comprehensive error handling with recovery actions:

function AuthErrorHandler() {
  const { error, signIn, refresh } = useBitcoinAuth();
  
  const getErrorMessage = (error) => {
    switch (error?.code) {
      case 'INVALID_SIGNATURE':
        return 'Invalid Bitcoin signature. Please try again.';
      case 'EXPIRED_SESSION':
        return 'Your session has expired. Please sign in again.';
      case 'NETWORK_ERROR':
        return 'Network error. Please check your connection.';
      case 'BACKUP_CORRUPTED':
        return 'Backup file appears to be corrupted.';
      default:
        return error?.message || 'An unexpected error occurred.';
    }
  };
  
  const getRecoveryAction = (error) => {
    switch (error?.code) {
      case 'EXPIRED_SESSION':
        return () => signIn();
      case 'NETWORK_ERROR':
        return () => refresh();
      default:
        return null;
    }
  };
  
  if (!error) return null;
  
  const recoveryAction = getRecoveryAction(error);
  
  return (
    <div className="auth-error">
      <ErrorDisplay error={getErrorMessage(error)} />
      
      {recoveryAction && (
        <LoadingButton onClick={recoveryAction}>
          Try Again
        </LoadingButton>
      )}
    </div>
  );
}

Signature Generation

Bitcoin Message Signing

The hook handles Bitcoin signature generation internally for authentication:

function SignatureExample() {
  const { user, signIn } = useBitcoinAuth();
  
  // The hook internally handles:
  // 1. Generate challenge message with timestamp
  // 2. Sign with private key using Bitcoin Signed Message (BSM)
  // 3. Verify signature on server
  // 4. Create session with JWT token
  
  // Example of what happens internally:
  // const message = `Sign in to BigBlocks\nTimestamp: ${Date.now()}`;
  // const signature = await bitcoinSign(message, privateKey);
  // const response = await api.authenticate({ message, signature, publicKey });
  
  return (
    <div>
      <p>Authentication uses Bitcoin signatures internally</p>
      <p>No passwords or usernames needed!</p>
      <button onClick={() => signIn()}>
        Sign In (Generates Bitcoin Signature)
      </button>
    </div>
  );
}

Session Management

Automatic Session Handling

The hook manages session tokens and automatic refresh:

function SessionInfo() {
  const { user, refresh, isAuthenticated } = useBitcoinAuth();
  const [sessionInfo, setSessionInfo] = useState(null);
  
  useEffect(() => {
    if (isAuthenticated) {
      // Session is automatically managed by the hook
      // JWT tokens are refreshed before expiry
      // Session data is stored in secure HTTP-only cookies
      
      const checkSession = async () => {
        try {
          const response = await fetch('/api/auth/session');
          const data = await response.json();
          setSessionInfo(data);
        } catch (error) {
          console.error('Session check failed:', error);
        }
      };
      
      checkSession();
    }
  }, [isAuthenticated]);
  
  return (
    <div className="session-info">
      <h3>Session Management</h3>
      {sessionInfo && (
        <div>
          <p>Session ID: {sessionInfo.id}</p>
          <p>Expires: {new Date(sessionInfo.expires).toLocaleString()}</p>
          <p>Auto-refresh: Enabled</p>
        </div>
      )}
      <button onClick={refresh}>
        Manual Refresh
      </button>
    </div>
  );
}

Best Practices

  1. Check Authentication State: Always check isAuthenticated before accessing user data
  2. Handle Loading States: Show loading indicators during auth operations
  3. Error Boundaries: Wrap components using this hook in error boundaries
  4. Wallet Capabilities: Check hasWalletCapabilities before wallet operations
  5. Profile Switching: Update UI state when users switch profiles
  6. Session Persistence: The hook handles session persistence automatically
  7. Secure Storage: Private keys are always encrypted before storage

Technical Details

  • React Query Integration: Uses React Query for caching and real-time updates
  • Local Storage: Manages encrypted local storage for session persistence
  • WebSocket Support: Real-time updates for balance and profile changes
  • Signature Validation: All operations validated with Bitcoin signatures
  • Session Management: Automatic session refresh and token management
  • Time-bound Tokens: 10-minute validity window prevents replay attacks

Security Considerations

  • Private keys never exposed through the hook interface
  • All operations require valid Bitcoin signatures
  • Session tokens have limited lifetime with automatic refresh
  • Backup operations are always encrypted
  • OAuth linking requires existing authentication
  • Signatures include timestamps to prevent replay attacks

Requirements

  • Must be used within BitcoinAuthProvider context
  • Requires BitcoinQueryProvider for caching
  • Network connection required for authentication operations
  • Local storage available for session persistence
  • Modern browser with Web Crypto API support

Example: Complete Authentication Flow

function CompleteAuthExample() {
  const {
    user,
    isAuthenticated,
    isLoading,
    error,
    signIn,
    signOut,
    downloadBackup,
    hasWalletCapabilities,
    balance,
    address
  } = useBitcoinAuth();
  
  if (isLoading) {
    return <LoadingSpinner />;
  }
  
  if (error) {
    return <AuthErrorHandler error={error} />;
  }
  
  if (!isAuthenticated) {
    return (
      <AuthLayout>
        <LoginForm onSuccess={() => console.log('Signed in!')} />
      </AuthLayout>
    );
  }
  
  return (
    <div className="authenticated-app">
      <header>
        <h1>Welcome, {user.name}!</h1>
        <ProfileDropdownMenu />
      </header>
      
      <main>
        <section className="identity-info">
          <h2>Bitcoin Identity</h2>
          <p>BAP ID: {user.bapId}</p>
          <p>Public Key: {user.publicKey}</p>
          <p>Address: {address}</p>
        </section>
        
        {hasWalletCapabilities && (
          <section className="wallet-info">
            <h2>Wallet</h2>
            <p>Balance: {balance} BSV</p>
            <SendBSVButton />
          </section>
        )}
        
        <section className="actions">
          <button onClick={downloadBackup}>
            Download Backup
          </button>
          <button onClick={signOut}>
            Sign Out
          </button>
        </section>
      </main>
    </div>
  );
}