Backend Guide

Building the Server-Side Certification Engine with BSV SDK

This guide covers backend patterns for implementing certificate issuance, field encryption, mutual authentication middleware, and certificate-gated routes using the BSV SDK, wallet-toolbox-client, and auth-express-middleware.

Complete Code Repository: https://github.com/bsv-blockchain-demos/certification-platformarrow-up-right

All code examples in this guide are taken from the working implementation in the backend/ directory.


Table of Contents


Setup

Installation

Project Structure

Environment Configuration

Create .env:

Variable
Purpose

SERVER_PRIVATE_KEY

32-byte hex private key — this IS the server's identity

BSV_NETWORK

'test' or 'main' — determines chain for wallet services

WALLET_STORAGE_URL

Remote storage endpoint for the full Wallet

PORT

Express server port


Server Identity & Key Architecture

Pattern 1: Deriving the Certifier Identity

Every participant in the BSV certificate system has an identity derived from an elliptic curve key pair (secp256k1). The server's private key generates its public identity:

See full implementation: backend/src/wallet.ts

Where the Certifier Public Key Appears:

Key Derivation Chain:

Certificate Type

The certificate type is a base64-encoded string that categorizes the certificate. The SDK's Utils class handles encoding:

Utils.toArray(str, 'utf8') converts the string to a byte array. Utils.toBase64(bytes) encodes it. This is the standard way to create certificate type identifiers in the BSV SDK.


Wallet Configuration

Pattern 2: Two Wallet Tiers

The backend uses two different wallet types for different purposes:

ProtoWallet — Certificate Signing

Lightweight wallet created from just a PrivateKey. No storage, no network. Used exclusively for MasterCertificate.issueCertificateForSubject():

Why ProtoWallet? MasterCertificate.issueCertificateForSubject() only needs cryptographic operations (key derivation, encryption, signing). A ProtoWallet is sufficient and avoids the overhead of storage initialization.

Full Wallet — Auth Middleware

The auth middleware requires a full WalletInterface because it needs to decrypt certificate fields, manage session nonces, and respond to the client's auth protocol:

Construction Chain:

Why Two Wallets?

Operation
Needs Storage?
Needs Network?
Wallet

Issue certificates

No

No

ProtoWallet

Auth middleware (ECDH, sessions)

Yes

Yes

Full Wallet

Decrypt certificate fields

Yes

No

Full Wallet


Certificate Issuance

Pattern 3: MasterCertificate.issueCertificateForSubject()

The core issuance method creates a complete, encrypted, signed certificate for a given subject:

Parameters:

Parameter
Type
Value

certifierWallet

ProtoWallet

Server's lightweight wallet

subjectPublicKey

string

User's identity key from request body

fields

Record<string, string>

Plaintext fields to encrypt

certificateType

string

"Y2VydGlmaWNhdGlvbg=="

getRevocationOutpoint

() => Promise<string>

Returns "000...0.0"

What Happens Internally:

Returning the Certificate:

Field Encryption Model

Certificate fields use a two-layer encryption scheme based on ECDH key agreement:

Why Two Layers?

  1. Field values are encrypted with a shared key from ECDH

  2. The shared key is encrypted in the keyring, targeted at the subject's public key

This means only the subject (user) or the certifier (server) can decrypt the fields.

Revocation Outpoint Format

The revocationOutpoint must follow the format <txid>.<outputIndex>:

In production, this would point to a real UTXO. Spending that UTXO revokes the certificate.


Auth Middleware & Sessions

Pattern 4: createAuthMiddleware Configuration

@bsv/auth-express-middleware implements mutual authentication between the client (browser wallet) and server. It intercepts requests on protected routes:

Configuration Parameters:

Parameter
Type
Purpose

wallet

WalletInterface

Server's wallet — ECDH, decryption, session signing

certificatesToRequest.certifiers

string[]

Only accept certs from these public keys

certificatesToRequest.types

Record<string, string[]>

Certificate types and which fields to request

sessionManager

SessionManager

Manages auth session state

onCertificatesReceived

Callback

Called when client presents certificates

logger

Console

Logging interface

logLevel

string

'debug', 'info', 'warn', 'error'

Session Negotiation Protocol

SessionManager

SessionManager from @bsv/sdk manages the mapping between client identity keys and session tokens:


Certificate Verification & Field Decryption

Pattern 5: VerifiableCertificate

When the auth middleware receives certificates from a client, the onCertificatesReceived callback decrypts and verifies the certificate fields:

Decryption Flow:

onCertificatesReceived Callback

This callback fires when a client presents certificates during authentication:

Why the Server Can Decrypt

The server's wallet holds the same private key used as the certifier when issuing the certificate. Since field encryption keys are derived via ECDH between certifier and subject, the server has one side of the ECDH:

Verification Tracking

Use a simple in-memory map to track which users have verified certificates:


Protected Routes

Pattern 6: Certificate-Gated Endpoints

Routes placed after the auth middleware are automatically protected. The middleware adds req.auth.identityKey to authenticated requests:

Route Organization:


Certificate Revocation

Pattern 7: Session and Verification Cleanup

When a user revokes their certificate, clean up server-side state:

Revocation Flow:


Complete Server

Main Server Setup

See full implementation: backend/src/server.ts


Important Concepts

SDK Class Reference

Class
Import
Purpose

PrivateKey

@bsv/sdk

Server identity key

KeyDeriver

@bsv/sdk

Derives child keys from root private key

ProtoWallet

@bsv/sdk

Lightweight wallet for certificate signing

MasterCertificate

@bsv/sdk

Issues encrypted, signed certificates

VerifiableCertificate

@bsv/sdk

Wraps cert + keyring for field decryption

SessionManager

@bsv/sdk

Manages auth session state

Utils

@bsv/sdk

Base64 encoding, byte array conversions

Wallet

@bsv/wallet-toolbox-client

Full wallet implementation

WalletSigner

@bsv/wallet-toolbox-client

Transaction and message signing

WalletStorageManager

@bsv/wallet-toolbox-client

Manages storage providers

StorageClient

@bsv/wallet-toolbox-client

Connects to remote storage

Services

@bsv/wallet-toolbox-client

Network services (chain queries)

createAuthMiddleware

@bsv/auth-express-middleware

Factory for Express auth middleware

AuthRequest

@bsv/auth-express-middleware

Extended Request type with auth property

Route Architecture

Security Considerations

  1. Private Key Storage: The SERVER_PRIVATE_KEY should be stored securely (environment variable, secrets manager) — never committed to source control

  2. CORS: Configure origin to your frontend's domain in production

  3. HTTPS: Use TLS in production for all endpoints

  4. Revocation Outpoints: In production, use real UTXOs for certificate revocation tracking

  5. Rate Limiting: Add rate limits to /api/certify to prevent abuse

BRC Standards Implemented

BRC
Standard
Implementation

BRC-31

Auth Protocol

createAuthMiddleware + AuthFetch mutual authentication

BRC-42

Key Derivation

KeyDeriver derives child keys for field encryption

BRC-43

Security Levels

Certificate field keys use specific security levels in ECDH

BRC-52

Certificate Creation

MasterCertificate.issueCertificateForSubject()

BRC-53

Certificate Verification

VerifiableCertificate.decryptFields()

BRC-56

Wallet Wire Protocol

WalletClient communicates with extensions via BRC-56


Testing

Start the Server

Test Endpoints


Summary

This backend guide covered:

  • Server Identity — Deriving certifier public key from private key

  • Wallet Types — ProtoWallet for signing, full Wallet for auth middleware

  • Certificate IssuanceMasterCertificate.issueCertificateForSubject() with field encryption

  • Auth MiddlewarecreateAuthMiddleware for mutual authentication

  • Field DecryptionVerifiableCertificate.decryptFields() for server-side verification

  • Protected Routes — Certificate-gated endpoints with verification tracking

  • Revocation — Session and verification cleanup

These patterns form the foundation for building self-hosted certification servers on BSV.


Next Steps

Last updated