BigBlocks Docs
Components/Authentication

IdentityGeneration

Component for generating new Bitcoin identities or importing existing ones

A streamlined component that provides options to generate a new Bitcoin identity or import an existing backup. It offers a simple interface with two primary actions, perfect for onboarding flows.

Identity GenerationGenerate new Bitcoin identities or import existing ones with support for various formats.

Create Your Identity

Generate a new Bitcoin identity or import existing backup
1
Generate BAP KeysWe'll create a unique BAP identity that only you control
2
Create PasswordEncrypt your keys with a strong password
3
Save BackupDownload your encrypted backup for safekeeping
or

What is a BAP Identity?A BAP (Bitcoin Attestation Protocol) identity uses cryptographic keys to authenticate you across applications. While you'll create a password to encrypt and protect your keys locally, you won't need passwords to log into websites - your BAP ID proves who you are cryptographically.

Supported Formats
BAP MasterBAP MemberWIFSeed Phrase

Security Note: Generated identities use secure random number generation. Private keys are never transmitted and remain in your browser.

Installation

npx bigblocks add identity-generation

Import

import { IdentityGeneration } from 'bigblocks';

Props

PropTypeRequiredDefaultDescription
onGenerate() => voidYes-Handler when generate button is clicked
onImport(file: File) => voidYes-Handler when import file is selected
loadingbooleanNofalseShow loading state
errorstringNo-Error message to display
classNamestringNo-Additional CSS classes

Basic Usage

import { IdentityGeneration } from 'bigblocks';
import { useRouter } from 'next/navigation';

export default function OnboardingPage() {
  const router = useRouter();

  const handleGenerate = () => {
    // Navigate to identity creation flow
    router.push('/create-identity');
  };

  const handleImport = (file: File) => {
    // Process the imported file
    console.log('Importing backup file:', file.name);
    // Navigate to import flow
    router.push('/import-backup');
  };

  return (
    <IdentityGeneration
      onGenerate={handleGenerate}
      onImport={handleImport}
    />
  );
}

Advanced Usage

With Loading State

import { IdentityGeneration } from 'bigblocks';
import { useState } from 'react';

export default function LoadingExample() {
  const [loading, setLoading] = useState(false);

  const handleGenerate = async () => {
    setLoading(true);
    try {
      // Simulate async operation
      await new Promise(resolve => setTimeout(resolve, 2000));
      // Navigate or process
    } finally {
      setLoading(false);
    }
  };

  return (
    <IdentityGeneration
      onGenerate={handleGenerate}
      onImport={(file) => console.log(file)}
      loading={loading}
    />
  );
}

With Error Handling

import { IdentityGeneration } from 'bigblocks';
import { useState } from 'react';

export default function ErrorHandlingExample() {
  const [error, setError] = useState<string | undefined>();

  const handleImport = (file: File) => {
    setError(undefined);
    
    // Validate file
    if (!file.name.match(/\.(txt|json|enc)$/)) {
      setError('Invalid file type. Please select a backup file.');
      return;
    }
    
    if (file.size > 10 * 1024 * 1024) {
      setError('File too large. Maximum size is 10MB.');
      return;
    }
    
    // Process file
    processBackupFile(file);
  };

  return (
    <IdentityGeneration
      onGenerate={() => console.log('Generate clicked')}
      onImport={handleImport}
      error={error}
    />
  );
}

Custom Styling

import { IdentityGeneration } from 'bigblocks';

export default function StyledExample() {
  return (
    <div className="bg-gray-50 p-8 rounded-lg">
      <h2 className="text-2xl font-bold mb-6">Get Started</h2>
      <IdentityGeneration
        onGenerate={() => console.log('Generate')}
        onImport={(file) => console.log('Import', file)}
        className="max-w-md mx-auto"
      />
    </div>
  );
}

Common Patterns

In Onboarding Flow

import { IdentityGeneration } from 'bigblocks';
import { useState } from 'react';

export function OnboardingFlow() {
  const [step, setStep] = useState<'choice' | 'generate' | 'import'>('choice');

  return (
    <div className="min-h-screen flex items-center justify-center">
      {step === 'choice' && (
        <div>
          <h1 className="text-3xl font-bold mb-8 text-center">
            Welcome to BigBlocks
          </h1>
          <IdentityGeneration
            onGenerate={() => setStep('generate')}
            onImport={(file) => {
              // Store file for processing
              sessionStorage.setItem('importFile', file.name);
              setStep('import');
            }}
          />
        </div>
      )}
      
      {step === 'generate' && (
        <div>
          <h2>Generate New Identity</h2>
          {/* Identity creation component */}
        </div>
      )}
      
      {step === 'import' && (
        <div>
          <h2>Import Backup</h2>
          {/* Backup import component */}
        </div>
      )}
    </div>
  );
}

With File Processing

import { IdentityGeneration } from 'bigblocks';

export function ProcessingExample() {
  const processFile = async (file: File) => {
    const content = await file.text();
    
    // Detect format
    if (content.startsWith('U2FsdGVkX1')) {
      console.log('Processing encrypted backup');
      // Handle encrypted backup
    } else if (content.startsWith('{')) {
      console.log('Processing JSON backup');
      // Handle JSON backup
    } else {
      console.log('Processing WIF backup');
      // Handle WIF format
    }
  };

  return (
    <IdentityGeneration
      onGenerate={() => {
        console.log('Creating new identity');
      }}
      onImport={processFile}
    />
  );
}

With Navigation

import { IdentityGeneration } from 'bigblocks';
import { useRouter } from 'next/navigation';

export function NavigationExample() {
  const router = useRouter();

  return (
    <IdentityGeneration
      onGenerate={() => {
        router.push('/auth/create-identity');
      }}
      onImport={(file) => {
        // Store file reference
        const fileUrl = URL.createObjectURL(file);
        sessionStorage.setItem('importFileUrl', fileUrl);
        
        router.push('/auth/import-backup');
      }}
    />
  );
}

In Modal Dialog

import { IdentityGeneration } from 'bigblocks';
import { useState } from 'react';

export function ModalExample() {
  const [showModal, setShowModal] = useState(true);

  return (
    <>
      {showModal && (
        <div className="fixed inset-0 bg-black/50 flex items-center justify-center p-4">
          <div className="bg-white rounded-lg p-6 max-w-md w-full">
            <h2 className="text-xl font-bold mb-4">Get Started</h2>
            
            <IdentityGeneration
              onGenerate={() => {
                setShowModal(false);
                // Start generation flow
              }}
              onImport={(file) => {
                setShowModal(false);
                // Start import flow
              }}
            />
            
            <button
              onClick={() => setShowModal(false)}
              className="mt-4 text-sm text-gray-500"
            >
              Cancel
            </button>
          </div>
        </div>
      )}
    </>
  );
}

File Handling

The component uses a hidden file input that accepts common backup formats:

// Internal file input configuration
<input
  type="file"
  accept=".txt,.json,.enc"
  onChange={(e) => {
    const file = e.target.files?.[0];
    if (file) onImport(file);
  }}
/>

Styling

The component uses Radix Themes Button components and can be customized with the className prop:

/* Default button arrangement */
.identity-generation {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

/* Custom styling example */
.custom-identity-generation {
  max-width: 400px;
  margin: 0 auto;
}

Best Practices

  1. Clear Actions: The two buttons clearly indicate the available options
  2. Error Feedback: Always provide error messages for invalid files
  3. Loading States: Show loading state during async operations
  4. File Validation: Validate file type and size before processing
  5. Navigation: Handle navigation after user selection

Accessibility

  • Both buttons are keyboard accessible
  • Clear visual feedback for hover and focus states
  • Error messages are announced to screen readers
  • File input is properly labeled

Troubleshooting

Import Not Working

  • Check that onImport handler is defined
  • Verify file types are accepted
  • Ensure file input isn't blocked by browser

Generate Not Triggering

  • Verify onGenerate handler is provided
  • Check for JavaScript errors in console
  • Ensure component isn't disabled via loading state

Styling Issues

  • Check className is applied correctly
  • Verify Radix Themes is properly configured
  • Inspect for CSS conflicts

API Reference

This component provides a simple interface for choosing between generating a new Bitcoin identity or importing an existing backup.

Handler Types

type GenerateHandler = () => void;
type ImportHandler = (file: File) => void;

File Object

The File object passed to onImport contains:

interface File {
  name: string;
  size: number;
  type: string;
  lastModified: number;
  text(): Promise<string>;
  arrayBuffer(): Promise<ArrayBuffer>;
}

Notes for Improvement

Simplified Implementation: The actual component is much simpler than the prompt described. It lacks:

  • Built-in identity generation logic (just triggers a callback)
  • Multiple generation modes (mnemonic vs random)
  • Direct identity/backup object handling
  • showImport prop to hide import option
  • generateMode prop for different generation methods

The actual implementation is a basic choice component with two buttons that delegate all logic to the parent component via callbacks.