An Express.js middleware that implements BRC-103 Peer-to-Peer Mutual Authentication via BRC-104 HTTP Transport. This library makes it easy to mutually authenticate and exchange verifiable certificates between clients and servers in a standardized way.
By layering BRC-103 on top of Express, you can:
- Perform a cryptographic handshake between two peers (your server and an external wallet/user).
- Request or respond with certificates that verify user identity or attributes.
- Enforce mutual authentication for your APIs, ensuring that each side proves its identity, without passwords or reliance on centralized authentication providers.
- Optionally enable selective disclosure of certificate fields.
- Background
- Features
- Installation
- Quick Start
- Detailed Usage
- API Reference
- Examples
- Security Considerations
- Resources & References
- License
BRC-103 is a specification for mutual authentication and certificate exchange over a peer-to-peer channel. It uses nonce-based challenges, digital signatures, and an optional selective disclosure mechanism for certificates. BRC-104 defines how to transport these messages specifically over HTTP, describing custom headers and the .well-known/auth
endpoint.
@bsv/auth-express-middleware
abstracts the complexities of these specs behind a typical Express middleware. It verifies BRC-103/104–compliant requests and properly signs responses, all while letting you continue to write normal Express code for your routes.
-
Seamless Integration
Plug straight into your existing Express application—no need for rewriting your entire HTTP handling logic. -
Mutual Authentication
Authenticates both the server and the client cryptographically, preventing impersonation or MITM attacks. -
Certificate Handling
Request, receive, and verify BRC-103 identity certificates. Includes utility methods to request additional certificates from the client. -
Selective Disclosure
Supports BRC-103’s concept of revealing only certain fields in a certificate, helping to preserve privacy for you and your users while verifying necessary information. -
Extendable
Provide a customSessionManager
or plug in advanced logic for verifying user attributes.
npm i @bsv/auth-express-middleware
This package depends on Express.js (4.x or 5.x) and a BRC-100–capable wallet (e.g., the @bsv/sdk
implementation or your own code).
Below is the minimal setup to enable BRC-103 mutual authentication in your Express server:
import express from 'express'
import bodyParser from 'body-parser'
import { createAuthMiddleware } from '@bsv/auth-express-middleware'
import { ProtoWallet as Wallet } from '@bsv/sdk' // You need a wallet that supports BRC-100 keys & signing
// 1. Initialize your BSV wallet (manages keys and signs messages)
const wallet = new Wallet(new PrivateKey('...', 16))
// 2. Create the auth middleware
// - Set `allowUnauthenticated` to false to require mutual auth on every route
const authMiddleware = createAuthMiddleware({
wallet,
allowUnauthenticated: false
})
// 3. Create and configure the Express app
const app = express()
app.use(bodyParser.json())
// 4. Apply the auth middleware globally (or to specific routes)
app.use(authMiddleware)
// 5. Define your routes as usual
app.get('/', (req, res) => {
if (req.auth && req.auth.identityKey !== 'unknown') {
// The request is authenticated
res.send(`Hello, authenticated peer with public key: ${req.auth.identityKey}`)
} else {
// Not authenticated
res.status(401).send('Unauthorized')
}
})
app.listen(3000, () => {
console.log('Server is running on port 3000')
})
When the server receives a BRC-103 handshake or "general" message, @bsv/auth-express-middleware
automatically handles the cryptographic checks. Once verified, req.auth.identityKey
will hold the public key of the authenticated peer.
Use the factory function:
createAuthMiddleware({
wallet: myWallet,
allowUnauthenticated?: boolean,
sessionManager?: SessionManager,
certificatesToRequest?: RequestedCertificateSet,
onCertificatesReceived?: (senderPublicKey, certs, req, res, next) => void
})
wallet
(required): A wallet instance that implements signing and key management, typically from@bsv/sdk
or your own custom build.allowUnauthenticated
(default:false
): Iftrue
, requests without valid BRC-103 authentication will not be rejected. Instead,req.auth.identityKey
is set to"unknown"
.sessionManager
(optional): Customize session management (nonce tracking, etc.). By default, an internalSessionManager
is used.certificatesToRequest
(optional): A specification of which certificates (by type, fields, issuer) to request automatically from the peer.onCertificatesReceived
(optional): Callback invoked when the peer responds with Verifiable Certificates.
Simply call:
app.use(express.json()) // required before the middleware is used
app.use(createAuthMiddleware({ wallet: myWallet }))
You can also place the middleware at the route level:
app.post('/secure-upload', createAuthMiddleware({ wallet: myWallet }), (req, res) => {
// ...
})
If you set certificatesToRequest
, the middleware will attempt to request certificates from the client during the handshake. When certificates arrive, the onCertificatesReceived
callback (if provided) will fire:
function onCertificatesReceived(senderPublicKey, certs, req, res, next) {
// You can inspect the provided certificates here
console.log(`Received ${certs.length} certificate(s) from ${senderPublicKey}.`)
// Continue to next middleware or route handler
next()
}
const authMiddleware = createAuthMiddleware({
wallet,
certificatesToRequest: {
certifiers: ['<33-byte-pubkey-of-certifier>'],
types: {
'age-verification': ['dateOfBirth', 'country']
}
},
onCertificatesReceived
})
In your server logic, you can then verify or store these certificates as needed. Replace fields like age-verification
with an actual base64 certificate type.
Once a peer is authenticated, you'll have:
req.auth.identityKey
⇒ the authenticated user's 33-byte compressed public key (hex-encoded).req.body
⇒ your normal request body (parsed byexpress.json()
or similar).- Standard
req.headers
⇒ includesx-bsv-auth-*
headers with BRC-103 handshake data (for debugging).
If allowUnauthenticated
is false, any request without a valid handshake or signature is rejected with 401
automatically.
Returns an Express middleware function. Options:
wallet
: (required) A BRC-100 object implementing your signing and verification logic.sessionManager
: (optional) Manage nonces & state across requests.allowUnauthenticated
: (optional) If true, non-authenticated requests are allowed but marked asidentityKey: 'unknown'
.certificatesToRequest
: (optional) Automatic certificate request data structure.onCertificatesReceived
: (optional) A callback triggered when certs arrive from the client.
import express from 'express'
import { createAuthMiddleware } from '@bsv/auth-express-middleware'
import { Wallet } from '@your/bsv-wallet'
const app = express()
const wallet = new Wallet({ /* config for your keys */ })
app.use(express.json())
app.use(createAuthMiddleware({ wallet }))
app.get('/protected', (req, res) => {
if (req.auth && req.auth.identityKey !== 'unknown') {
return res.send('You are authenticated via BRC-103!')
}
res.status(401).send('Unauthorized')
})
app.listen(3000, () => console.log('BRC-103 server listening on port 3000!'))
import express from 'express'
import { createAuthMiddleware } from '@bsv/auth-express-middleware'
import { Wallet } from '@your/bsv-wallet'
const wallet = new Wallet()
function onCertificatesReceived(senderPublicKey, certs, req, res, next) {
console.log(`Received certs from ${senderPublicKey}`, certs)
next()
}
const authMiddleware = createAuthMiddleware({
wallet,
certificatesToRequest: {
certifiers: ['<certifier-pubkey-hex>'],
types: {
'someCertificateType': ['fieldA', 'fieldB']
}
},
onCertificatesReceived
})
const app = express()
app.use(express.json())
app.use(authMiddleware)
app.listen(3000, () => console.log('Server up!'))
- TLS Encryption: Although BRC-103 messages are authenticated, the protocol does not encrypt the entire payload. It's recommended to serve your Express app over HTTPS to maintain confidentiality.
- Nonce Replay Prevention: This library implements a
SessionManager
that automatically rejects nonces not bound by the server's private key. - Transport-Only: BRC-104's HTTP specification focuses on message authenticity, not on anonymizing request metadata.
- Certificate Revocation: BRC-103 allows for revocation references (
revocationOutpoint
). Ensure your app checks the blockchain or an appropriate certificate revocation overlay service if you require strict revocation handling.
- BRC-103 Spec – Mutual authentication & certificate exchange.
- BRC-104 Spec – HTTP Transport for BRC-103.
- @bsv/sdk – BSV TypeScript SDK (often used for cryptographic utilities, wallet logic, etc.).
- Express.js – Web framework for Node.js.
Happy hacking! If you have questions, suggestions, or want to contribute improvements, feel free to open an issue or PR in our repository.