BigBlocks Docs
Components/Authentication

createAuthManager

Factory function for creating pre-configured AuthManager instances

A factory function that creates and configures AuthManager instances for Bitcoin authentication. Provides a comprehensive API for managing authentication state, sessions, and wallet operations.

Installation

npx bigblocks add create-auth-manager

Import

import { createAuthManager } from 'bigblocks';

Basic Usage

import { createAuthManager } from 'bigblocks';

// Create auth manager instance
const authManager = createAuthManager({
  apiUrl: '/api'
});

// Use in your application
async function handleSignIn(password: string) {
  try {
    await authManager.signIn(password);
    console.log('Signed in successfully');
  } catch (error) {
    console.error('Sign in failed:', error);
  }
}

Configuration

interface BitcoinAuthConfig {
  apiUrl: string;              // API endpoint URL
  debug?: boolean;             // Enable debug logging
  backupTypes?: string[];      // Supported backup types
}

API Methods

The AuthManager instance provides these methods:

Authentication

// Sign in with password
await authManager.signIn(password: string);

// Sign up with new account
await authManager.signUp(password: string);

// Sign out
await authManager.signOut();

// Validate password
const isValid = await authManager.validatePassword(password: string);

State Management

// Get current state
const state = authManager.getState();
// Returns: { isAuthenticated, isLoading, user, error }

// Subscribe to state changes
const unsubscribe = authManager.subscribe((event) => {
  console.log('Auth event:', event.type, event.data);
});

// Cleanup
unsubscribe();

Backup Operations

// Generate backup
const backup = authManager.generateBackup();

// Import backup from file
await authManager.importBackup(file: File);

OAuth Integration

// Link OAuth provider
await authManager.linkOAuth('google');

// Handle OAuth callback
await authManager.handleOAuthCallback('google', true);

Wallet Features

// Get wallet extension (if user has wallet capabilities)
const walletExt = await authManager.getWalletExtension();

Actions Helper

// Get all actions as a convenient object
const actions = authManager.getActions();
// Includes: signIn, signUp, signOut, importBackup, linkOAuth, etc.

Advanced Usage

With React Hook

import { createAuthManager } from 'bigblocks';
import { useState, useEffect, useCallback } from 'react';

function useAuthManager(config) {
  const [authManager] = useState(() => createAuthManager(config));
  const [state, setState] = useState(authManager.getState());

  useEffect(() => {
    const unsubscribe = authManager.subscribe((event) => {
      setState(authManager.getState());
    });

    return unsubscribe;
  }, [authManager]);

  const signIn = useCallback(async (password) => {
    await authManager.signIn(password);
  }, [authManager]);

  const signOut = useCallback(async () => {
    await authManager.signOut();
  }, [authManager]);

  return {
    ...state,
    signIn,
    signOut,
    authManager
  };
}

// Usage
function LoginComponent() {
  const { isAuthenticated, user, signIn, signOut } = useAuthManager({
    apiUrl: '/api'
  });

  if (isAuthenticated) {
    return (
      <div>
        <p>Welcome, {user.name}!</p>
        <button onClick={signOut}>Sign Out</button>
      </div>
    );
  }

  return (
    <form onSubmit={async (e) => {
      e.preventDefault();
      const password = e.target.password.value;
      await signIn(password);
    }}>
      <input type="password" name="password" required />
      <button type="submit">Sign In</button>
    </form>
  );
}

With Error Handling

import { createAuthManager } from 'bigblocks';

const authManager = createAuthManager({
  apiUrl: '/api',
  debug: true
});

// Subscribe to all events
authManager.subscribe((event) => {
  switch (event.type) {
    case 'AUTH_ERROR':
      console.error('Auth error:', event.data.error);
      showErrorNotification(event.data.error.message);
      break;
      
    case 'STATE_CHANGE':
      console.log('State changed:', event.data);
      break;
      
    case 'SESSION_CREATED':
      console.log('Session created for:', event.data.user.name);
      trackLogin(event.data.user);
      break;
      
    case 'SESSION_DESTROYED':
      console.log('Session destroyed');
      trackLogout();
      break;
  }
});

With Backup Management

import { createAuthManager } from 'bigblocks';

const authManager = createAuthManager({
  apiUrl: '/api',
  backupTypes: ['BapMasterBackup', 'OneSatBackup', 'WifBackup']
});

// Export backup
function exportBackup() {
  const backup = authManager.generateBackup();
  const blob = new Blob([JSON.stringify(backup)], { 
    type: 'application/json' 
  });
  const url = URL.createObjectURL(blob);
  
  const a = document.createElement('a');
  a.href = url;
  a.download = 'bitcoin-wallet-backup.json';
  a.click();
}

// Import backup
async function importBackup(file) {
  try {
    await authManager.importBackup(file);
    console.log('Backup imported successfully');
  } catch (error) {
    console.error('Import failed:', error);
  }
}

With OAuth Flow

import { createAuthManager } from 'bigblocks';

const authManager = createAuthManager({
  apiUrl: '/api'
});

// OAuth link button
function OAuthLinkButton({ provider }) {
  const handleLink = async () => {
    try {
      await authManager.linkOAuth(provider);
      // This will redirect to OAuth provider
    } catch (error) {
      console.error('OAuth link failed:', error);
    }
  };

  return (
    <button onClick={handleLink}>
      Link {provider}
    </button>
  );
}

// OAuth callback handler
async function handleOAuthReturn() {
  const params = new URLSearchParams(window.location.search);
  const provider = params.get('provider');
  const success = params.get('success') === 'true';
  
  if (provider) {
    await authManager.handleOAuthCallback(provider, success);
  }
}

Event Types

The AuthManager emits these events:

type AuthEvent = 
  | { type: 'STATE_CHANGE'; data: AuthState }
  | { type: 'AUTH_ERROR'; data: { error: Error } }
  | { type: 'SESSION_CREATED'; data: { user: AuthUser } }
  | { type: 'SESSION_DESTROYED'; data: null }
  | { type: 'BACKUP_IMPORTED'; data: { type: string } }
  | { type: 'OAUTH_LINKED'; data: { provider: string } };

State Structure

interface AuthState {
  isAuthenticated: boolean;
  isLoading: boolean;
  user: AuthUser | null;
  error: Error | null;
}

interface AuthUser {
  bapId: string;
  name?: string;
  address?: string;
  hasWalletCapabilities?: boolean;
  createdAt?: Date;
  // ... other user properties
}

Common Patterns

Protected Routes

function ProtectedRoute({ children }) {
  const authManager = createAuthManager({ apiUrl: '/api' });
  const [state, setState] = useState(authManager.getState());

  useEffect(() => {
    const unsubscribe = authManager.subscribe(() => {
      setState(authManager.getState());
    });
    return unsubscribe;
  }, []);

  if (!state.isAuthenticated) {
    return <Navigate to="/signin" />;
  }

  return children;
}

Session Persistence

function PersistentAuth() {
  const authManager = createAuthManager({ apiUrl: '/api' });
  
  useEffect(() => {
    // Check for existing session on mount
    const checkSession = async () => {
      const encryptedBackup = localStorage.getItem('encryptedBackup');
      if (encryptedBackup) {
        // Session exists, validate it
        const state = authManager.getState();
        if (!state.isAuthenticated) {
          // Re-authenticate if needed
          console.log('Session expired, please sign in again');
        }
      }
    };
    
    checkSession();
  }, []);
}

Multi-Provider Support

function MultiProviderAuth() {
  const authManager = createAuthManager({
    apiUrl: '/api',
    backupTypes: ['BapMasterBackup', 'OneSatBackup', 'WifBackup']
  });

  const handleImport = async (file) => {
    try {
      await authManager.importBackup(file);
      
      // Check which type was imported
      const state = authManager.getState();
      console.log('Imported user:', state.user);
      
    } catch (error) {
      if (error.message.includes('password')) {
        // Prompt for password
        const password = prompt('Enter backup password:');
        // Retry import with password
      }
    }
  };
}

Error Handling

authManager.subscribe((event) => {
  if (event.type === 'AUTH_ERROR') {
    const error = event.data.error;
    
    switch (error.code) {
      case 'INVALID_PASSWORD':
        showError('Invalid password');
        break;
        
      case 'NETWORK_ERROR':
        showError('Network connection failed');
        break;
        
      case 'SESSION_EXPIRED':
        showError('Session expired, please sign in again');
        break;
        
      case 'BACKUP_CORRUPTED':
        showError('Backup file is corrupted');
        break;
        
      default:
        showError('Authentication failed');
    }
  }
});

Best Practices

  1. Single Instance: Create one AuthManager instance per app
  2. Error Handling: Always handle authentication errors
  3. State Subscription: Subscribe to state changes for reactive UI
  4. Cleanup: Unsubscribe from events when components unmount
  5. Security: Never log sensitive data like passwords or private keys

Troubleshooting

State Not Updating

// Ensure you're subscribing to changes
const unsubscribe = authManager.subscribe((event) => {
  // Update your UI state here
  updateUIState(authManager.getState());
});

// Don't forget to cleanup
return () => unsubscribe();

Import Failing

// Check supported backup types
console.log('Supported types:', authManager.options?.backupTypes);

// Validate file before import
if (!file.type.match(/json|text/)) {
  throw new Error('Invalid file type');
}

API Reference

AuthManager Class

The AuthManager provides a complete authentication system with:

  • Password-based authentication
  • Backup import/export
  • OAuth provider linking
  • Session management
  • Event-driven state updates
  • Wallet integration support

All methods are async and return promises for easy integration with modern JavaScript applications.