Skip to content

bitcoin-sv/auth-express-middleware

Repository files navigation

@bsv/auth-express-middleware

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.

Table of Contents

  1. Background
  2. Features
  3. Installation
  4. Quick Start
  5. Detailed Usage
  6. API Reference
  7. Examples
  8. Security Considerations
  9. Resources & References
  10. License

Background

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.


Features

  • 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 custom SessionManager or plug in advanced logic for verifying user attributes.


Installation

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).


Quick Start

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.


Detailed Usage

Creating the Middleware

Use the factory function:

createAuthMiddleware({
  wallet: myWallet, 
  allowUnauthenticated?: boolean,
  sessionManager?: SessionManager,
  certificatesToRequest?: RequestedCertificateSet,
  onCertificatesReceived?: (senderPublicKey, certs, req, res, next) => void
})

Options

  • wallet (required): A wallet instance that implements signing and key management, typically from @bsv/sdk or your own custom build.
  • allowUnauthenticated (default: false): If true, 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 internal SessionManager 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.

Injecting the Middleware into Express

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) => {
  // ...
})

Handling Certificates

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.

Interpreting Authenticated Requests

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 by express.json() or similar).
  • Standard req.headers ⇒ includes x-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.


API Reference

createAuthMiddleware(options: AuthMiddlewareOptions)

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 as identityKey: 'unknown'.
  • certificatesToRequest: (optional) Automatic certificate request data structure.
  • onCertificatesReceived: (optional) A callback triggered when certs arrive from the client.

Examples

1. Minimal Setup

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!'))

2. Requesting Certificates at Handshake

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!'))

Security Considerations

  1. 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.
  2. Nonce Replay Prevention: This library implements a SessionManager that automatically rejects nonces not bound by the server's private key.
  3. Transport-Only: BRC-104's HTTP specification focuses on message authenticity, not on anonymizing request metadata.
  4. 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.

Resources & References

  • 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.

License

Open BSV License


Happy hacking! If you have questions, suggestions, or want to contribute improvements, feel free to open an issue or PR in our repository.

About

BSV Blockchain mutual-authentication express middleware

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published