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-authImport
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 signaturePOST /signout- Sign out and clear sessionGET /session- Get current sessionPOST /verify- Verify authentication tokenPOST /backup/generate- Generate wallet backupPOST /backup/encrypt- Encrypt backupPOST /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
- Security: Always use HTTPS in production
- Time Window: Set appropriate signature expiry time
- Storage: Use persistent storage for production
- Error Handling: Provide clear error messages
- 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:'
});Related Components
- createAuthManager - Higher-level auth manager
- BitcoinAuthProvider - React provider
- AuthButton - Pre-built auth UI
- Framework adapters for Next.js, Express, Astro
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.