<>ts-stack
Get StartedArchitecturePackagesSpecsGuides
⌘K
Reference
Home
Get StartedOverviewInstallChoose your stackKey concepts
ArchitectureOverviewStack layersBEEF (BRC-62)BRC-100 Wallet InterfaceIdentity & AuthConformance pipeline
PackagesOverviewSDKWalletNetworkOverlaysMessagingMiddleware
@bsv/auth-express-middleware@bsv/payment-express-middleware@bsv/402-pay
Helpers
InfrastructureOverviewmessage-box-serveroverlay-serveruhrp-server-basicuhrp-server-cloud-bucketwabwallet-infrachaintracks-server
SpecsOverviewBRC-100 Wallet InterfaceOverlay HTTPMessage-box HTTPAuthsocket (WebSocket)BRC-31 Auth HandshakeBRC-29 Peer PaymentBRC-121 / HTTP 402ARC BroadcastMerkle ServiceStorage AdapterGASP SyncUHRPAir-Gap Optical (BRC-141)
ConformanceOverviewVector catalogTS runnerContributing vectors
GuidesOverviewBuild a wallet-aware appRun an overlay nodePeer-to-peer messagingHTTP 402 payments
ReferenceOverviewBRC indexRepository health
AboutVersioningContributingDoc agentDocumentation sources
npmhttps://www.npmjs.com/package/@bsv/auth-express-middlewarev2.2.2API reference (TypeDoc) ↗
Loading…
Edit this page on GitHub
© 2026 BSV Blockchain. ts-stack is open-source.
GitHubContributingVersioning

@bsv/auth-express-middleware

Express transport for BRC-103 peer-to-peer mutual authentication over BRC-104 HTTP. It handles the public handshake, verifies authenticated application requests, signs responses, and optionally exchanges verifiable certificates.

Install

bash
npm install @bsv/auth-express-middleware @bsv/sdk express

Node.js 22 or newer and Express 4.18 or newer are required. The package uses the application's peer-provided Express runtime and type graph and provides native ESM and CommonJS entry points with matching declarations.

Quick start

ts
import express from 'express'
import { PrivateKey, ProtoWallet } from '@bsv/sdk'
import { createAuthMiddleware, type AuthRequest } from '@bsv/auth-express-middleware'

const wallet = new ProtoWallet(PrivateKey.fromRandom())
const app = express()

app.use(express.json())
app.use(createAuthMiddleware({ wallet }))

app.get('/private', (req: AuthRequest, res) => {
  res.json({ identityKey: req.auth?.identityKey })
})

Authentication is required by default. allowUnauthenticated: true permits requests without auth and marks them with identity key unknown; that value must never be treated as authorization.

Configuration

ts
app.use(
  createAuthMiddleware({
    wallet,
    allowUnauthenticated: false,
    sessionManager,
    certificatesToRequest,
    onCertificatesReceived,
    logger,
    logLevel: 'error',
    transportLimits: {
      requestTimeoutMs: 30_000,
      maxPendingRequests: 1_000,
      maxResponseBytes: 8 * 1024 * 1024
    }
  })
)

transportLimits bounds pending handshakes, verification listeners, certificate waits, and response-signing state. maxResponseBytes also bounds files passed to res.sendFile; oversized application responses fail closed with a signed 413. The default is 8 MiB. Operators may set it to -1 only when the embedding service enforces an equivalent response budget. Malformed requests are rejected before state allocation. At capacity, the middleware fails closed with 503.

The exact /.well-known/auth endpoint remains public because it establishes the session. Similar path prefixes receive normal auth treatment.

Scaled deployment

The default SDK SessionManager is process-local. A load-balanced service must inject a shared AsyncSessionManager so every replica can resolve the same handshake/session state:

ts
import type { AsyncSessionManager } from '@bsv/sdk'

app.use(
  createAuthMiddleware({
    wallet,
    sessionManager: sharedSessionManager satisfies AsyncSessionManager
  })
)

Use storage with appropriate atomicity, expiry, availability, and encryption. Sticky routing does not preserve state through process replacement.

Certificate handling

ts
app.use(
  createAuthMiddleware({
    wallet,
    certificatesToRequest: {
      certifiers: ['<compressed-certifier-public-key>'],
      types: { '<base64-certificate-type>': ['firstName'] }
    },
    async onCertificatesReceived(senderPublicKey, certificates, req, res, next) {
      await authorizeDisclosedFields(senderPublicKey, certificates)
      next()
    }
  })
)

Applications remain responsible for authorization, revocation checks, and storage of disclosed fields. Callback errors produce generic public responses; certificate bodies and internal errors are not logged by default or returned.

Browser and public-service policy

The middleware does not hard-code CORS, CSP, or origin restrictions. Public services can remain accessible across browser apps, WUI, mobile clients, and unknown domains by default, while an operator may opt into a configurable allowlist at the application or edge.

For browsers, handle OPTIONS before auth and expose required x-bsv-auth-* headers. Do not combine wildcard origins with credentialed CORS. CSP is primarily a document policy and is not a substitute for API CORS.

Security and operations

  • Use HTTPS; mutual authentication does not encrypt all HTTP data.
  • Parse bodies before auth so signed and routed values match.
  • Install one auth wrapper per request path.
  • Keep finite timeouts/response sizes/capacity and alert on 408, 413, and 503.
  • Keep authentication separate from application authorization.
  • Do not log raw headers, signatures, certificates, bodies, or wallet objects.
  • Public errors are stable and omit internal exception text.

Public API

Runtime:

  • createAuthMiddleware
  • ExpressTransport

Types:

  • AuthMiddlewareOptions
  • AuthRequest
  • AuthTransportLimits
  • LogLevel

Related packages

  • @bsv/payment-express-middleware — authenticated payment gating; runs after auth
  • @bsv/authsocket / @bsv/authsocket-client — WebSocket mutual auth
  • @bsv/sdk — wallet, peer, session, and AuthFetch implementation

References

  • Package README
  • npm
  • BRC-103
  • BRC-104