BigBlocks Docs
Components/Authentication

createBigBlocksAuth

Framework-agnostic authentication core for Bitcoin-based authentication

A framework-agnostic authentication core that provides Bitcoin-based authentication primitives for any JavaScript framework. Creates a low-level auth instance with a universal handler pattern for maximum flexibility.

Installation

npx bigblocks add create-bigblocks-auth

Import

import { createBigBlocksAuth } from 'bigblocks';

Basic Usage

import { createBigBlocksAuth } from 'bigblocks';

// Create authentication instance
const auth = createBigBlocksAuth({
  verifySignatures: true,
  timeWindow: 600000, // 10 minutes
  basePath: '/api/auth'
});

// Use the universal handler
const response = await auth.handler(request);

Configuration

interface BigBlocksAuthOptions {
  verifySignatures?: boolean;              // Verify Bitcoin signatures (default: true)
  timeWindow?: number;                      // Signature validity window in ms (default: 600000)
  bodyEncoding?: 'hex' | 'base64' | 'utf8'; // Request body encoding (default: 'utf8')
  basePath?: string;                        // Base API path (default: '/api/auth')
  storage?: StorageAdapter;                 // Storage adapter
  storageNamespace?: string;                // Storage key prefix
  backupTypes?: string[];                   // Supported backup types
}

Core API

The auth instance provides:

Universal Handler

// Handle any authentication request
const response = await auth.handler(request);

API Methods

// Verify authentication
const result = await auth.api.verifyAuth({
  address: 'bitcoin-address',
  idKey: 'bap-id-key',
  authToken: 'signed-message',
  requestPath: '/api/protected',
  body: 'request-body'
});

// Get session from headers
const session = await auth.api.getSession(headers);

// Generate backup
const backup = auth.api.generateBackup();

// Encrypt backup
const encrypted = await auth.api.encryptBackup(backup, password);

// Decrypt backup
const decrypted = await auth.api.decryptBackup(encrypted, password);

Framework Integrations

Next.js App Router

// app/api/auth/[...auth]/route.ts
import { createBigBlocksAuth } from 'bigblocks';

const auth = createBigBlocksAuth({
  basePath: '/api/auth'
});

export async function GET(request: Request) {
  return auth.handler(request);
}

export async function POST(request: Request) {
  return auth.handler(request);
}

Express.js

import express from 'express';
import { createBigBlocksAuth } from 'bigblocks';

const app = express();
const auth = createBigBlocksAuth();

// Convert Express request to standard Request
app.use('/api/auth/*', async (req, res) => {
  const url = `http://localhost${req.originalUrl}`;
  const request = new Request(url, {
    method: req.method,
    headers: req.headers,
    body: req.method !== 'GET' ? JSON.stringify(req.body) : undefined
  });
  
  const response = await auth.handler(request);
  const body = await response.text();
  
  res.status(response.status).send(body);
});

Fastify

import fastify from 'fastify';
import { createBigBlocksAuth } from 'bigblocks';

const app = fastify();
const auth = createBigBlocksAuth();

app.all('/api/auth/*', async (request, reply) => {
  const standardRequest = new Request(request.url, {
    method: request.method,
    headers: request.headers,
    body: request.body ? JSON.stringify(request.body) : undefined
  });
  
  const response = await auth.handler(standardRequest);
  const body = await response.text();
  
  reply.code(response.status).send(body);
});

Hono

import { Hono } from 'hono';
import { createBigBlocksAuth } from 'bigblocks';

const app = new Hono();
const auth = createBigBlocksAuth();

app.all('/api/auth/*', async (c) => {
  const response = await auth.handler(c.req.raw);
  return response;
});

Advanced Usage

Custom Storage Adapter

import { createBigBlocksAuth } from 'bigblocks';

class RedisStorageAdapter {
  async get(key: string): Promise<string | null> {
    return redis.get(key);
  }
  
  async set(key: string, value: string): Promise<void> {
    await redis.set(key, value);
  }
  
  async delete(key: string): Promise<void> {
    await redis.del(key);
  }
}

const auth = createBigBlocksAuth({
  storage: new RedisStorageAdapter(),
  storageNamespace: 'bigblocks:auth:'
});

Custom Verification

const auth = createBigBlocksAuth({
  verifySignatures: true,
  timeWindow: 300000, // 5 minutes for stricter security
  bodyEncoding: 'base64' // For binary data
});

// Manual verification
async function verifyRequest(req: Request) {
  const authHeader = req.headers.get('X-Auth-Token');
  if (!authHeader) {
    return { success: false, error: 'Missing auth token' };
  }
  
  const [address, idKey, signature] = authHeader.split(':');
  
  return auth.api.verifyAuth({
    address,
    idKey,
    authToken: signature,
    requestPath: new URL(req.url).pathname,
    body: await req.text()
  });
}

Session Management

const auth = createBigBlocksAuth();

// Middleware to attach session
async function sessionMiddleware(req: Request): Promise<Request> {
  const session = await auth.api.getSession(req.headers);
  
  if (session) {
    // Attach session to request
    (req as any).session = session;
  }
  
  return req;
}

// Protected route handler
async function protectedHandler(req: Request) {
  const session = (req as any).session;
  
  if (!session) {
    return new Response('Unauthorized', { status: 401 });
  }
  
  return new Response(JSON.stringify({
    message: 'Protected data',
    user: session.user
  }));
}

Backup Operations

const auth = createBigBlocksAuth({
  backupTypes: ['BapMasterBackup', 'OneSatBackup', 'WifBackup']
});

// Generate and encrypt backup
async function exportBackup(password: string) {
  const backup = auth.api.generateBackup();
  const encrypted = await auth.api.encryptBackup(backup, password);
  
  // Save to file
  const blob = new Blob([encrypted], { type: 'text/plain' });
  const url = URL.createObjectURL(blob);
  
  const a = document.createElement('a');
  a.href = url;
  a.download = 'wallet-backup.txt';
  a.click();
}

// Import and decrypt backup
async function importBackup(file: File, password: string) {
  const encrypted = await file.text();
  const backup = await auth.api.decryptBackup(encrypted, password);
  
  // Process backup
  console.log('Imported backup:', backup);
  return backup;
}

Authentication Flow

Client-Side

// Sign authentication request
async function authenticatedFetch(url: string, options?: RequestInit) {
  const { address, idKey, privateKey } = getWalletInfo();
  
  // Create message to sign
  const timestamp = Date.now();
  const body = options?.body || '';
  const message = `${url}:${body}:${timestamp}`;
  
  // Sign with Bitcoin private key
  const signature = await signMessage(message, privateKey);
  
  // Create auth token
  const authToken = `${address}:${idKey}:${signature}:${timestamp}`;
  
  return fetch(url, {
    ...options,
    headers: {
      ...options?.headers,
      'X-Auth-Token': authToken
    }
  });
}

Server-Side Verification

const auth = createBigBlocksAuth();

async function handleProtectedRoute(request: Request) {
  // Auth handler automatically verifies the signature
  const authResponse = await auth.handler(request);
  
  if (!authResponse.ok) {
    return authResponse; // Return error response
  }
  
  // Get verified session
  const session = await auth.api.getSession(request.headers);
  
  // Process authenticated request
  return new Response(JSON.stringify({
    message: 'Success',
    user: session?.user
  }));
}

Route Patterns

The universal handler supports these routes:

  • POST /signin - Sign in with Bitcoin signature
  • POST /signout - Sign out and clear session
  • GET /session - Get current session
  • POST /verify - Verify authentication token
  • POST /backup/generate - Generate wallet backup
  • POST /backup/encrypt - Encrypt backup
  • POST /backup/decrypt - Decrypt backup

Error Handling

const auth = createBigBlocksAuth();

async function handleAuthError(request: Request) {
  try {
    const response = await auth.handler(request);
    return response;
  } catch (error) {
    console.error('Auth error:', error);
    
    if (error.message.includes('signature')) {
      return new Response('Invalid signature', { status: 401 });
    }
    
    if (error.message.includes('expired')) {
      return new Response('Token expired', { status: 401 });
    }
    
    return new Response('Authentication failed', { status: 500 });
  }
}

Best Practices

  1. Security: Always use HTTPS in production
  2. Time Window: Set appropriate signature expiry time
  3. Storage: Use persistent storage for production
  4. Error Handling: Provide clear error messages
  5. Logging: Log authentication events for security

Types

interface BigBlocksAuthPayload {
  address: string;       // Bitcoin address
  idKey: string;         // BAP identity key
  authToken: string;     // Signed message
  requestPath: string;   // API path
  body: string;          // Request body
  timestamp?: string;    // Optional timestamp
}

interface BigBlocksAuthResult {
  success: boolean;
  user?: AuthUser;
  error?: string;
}

interface BigBlocksSession {
  user: AuthUser;
  sessionId: string;
  expiresAt: Date;
}

Troubleshooting

Signature Verification Failed

// Check time synchronization
const auth = createBigBlocksAuth({
  timeWindow: 1200000 // 20 minutes for testing
});

// Log verification details
auth.api.verifyAuth(payload).catch(error => {
  console.error('Verification failed:', error);
  console.log('Payload:', payload);
});

Session Not Persisting

// Ensure storage is configured
const auth = createBigBlocksAuth({
  storage: new PersistentStorageAdapter(),
  storageNamespace: 'myapp:auth:'
});

Notes for Improvement

Simplified Implementation: The actual component is a universal handler pattern following the Better Auth approach. It's more focused on:

  • Universal request/response handling
  • Bitcoin signature verification
  • Session management via headers
  • Backup encryption/decryption utilities

The prompt described a more complex client-side focused API, while the actual implementation is server-oriented with a clean handler pattern for easy framework integration.