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
- Check Authentication State: Always check
isAuthenticated
before accessing user data - Handle Loading States: Show loading indicators during auth operations
- Error Boundaries: Wrap components using this hook in error boundaries
- Wallet Capabilities: Check
hasWalletCapabilities
before wallet operations - Profile Switching: Update UI state when users switch profiles
- Session Persistence: The hook handles session persistence automatically
- 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>
);
}
Related Components
- AuthButton - Pre-built authentication button
- LoginForm - Complete login form component
- ProfileEditor - Profile management UI
- BackupDownload - Backup management component
- BitcoinAuthProvider - Required provider component