HTTP Transport for BRC-103 Mutual Authentication

1. Abstract

This specification defines how to transport BRC-103 [1] mutual authentication messages via HTTP. It introduces:

  • A .well-known/auth endpoint for non-general BRC-103 messages (e.g. handshake, certificate requests).

  • A mechanism for embedding “general” messages in normal HTTP requests/responses using custom x-bsv-auth headers and an encoded request/response “payload.”

  • Clear rules for which HTTP headers are included in the signature and which are excluded, ensuring consistent signing and verification on both client and server.

  • An approach for referencing the remote peer’s identity key and session parameters in standard HTTP requests/responses.

By adopting this scheme, implementers can re-use BRC-103’s cryptographic handshake and selective certificate exchange logic in a typical browser–server or server–server HTTP environment.


2. Introduction

BRC-103 [1] defines a peer-to-peer mutual authentication flow but leaves the transport unspecified. This document describes an HTTP layering for that flow. It details:

  • Endpoints and message paths for BRC-103 handshake messages.

  • A scheme for “general” messages that carry an entire HTTP request/response inside a single BRC-103 message.

  • Custom HTTP headers that store BRC-103 parameters (nonces, signatures, identity keys, requested certificates, etc.).

  • Mechanisms to handle typical web scenarios such as 402 Payment Required or other status codes.

Where BRC-103 gives a general outline (initialRequest, initialResponse, general, certificateRequest, certificateResponse), BRC-104 explains how those messages appear as HTTP requests and HTTP responses.

3. Relationship to BRC-103

  • Mandatory Prerequisite: Implementers MUST implement or rely on BRC-103’s handshake, message types, and signature logic.

  • This specification extends BRC-103 by mapping each BRC-103 message type onto HTTP requests and responses, describing /.well-known/auth usage, specialized headers (x-bsv-auth-*), and the structured “payload” approach for general messages.

Whenever conflicts arise, BRC-103 is authoritative on handshake semantics and certificate exchange. BRC-104 only clarifies how to wrap those messages in HTTP.

4. Terminology & Definitions

  • BRC-103 Message: One of initialRequest, initialResponse, certificateRequest, certificateResponse, or general.

  • Non-General Message: A BRC-103 message of type initialRequest, initialResponse, certificateRequest, or certificateResponse.

  • General Message: A BRC-103 message of type general, used to transmit an entire HTTP request or response under the authenticated session.

  • Peer: A user agent (client) or server implementing the protocol.

  • x-bsv-auth- Headers: A family of custom HTTP headers that store BRC-103 parameters (identity key, nonce, signature, etc.).

  • x-bsv-payment Header: An optional header used for embedding BSV payment data (e.g. 402 flows).

  • .well-known/auth Endpoint: The canonical path for sending non-general messages as JSON in a POST body.

5. High-Level Overview

  1. Non-General BRC-103 messages (initialRequest, initialResponse, certificateRequest, certificateResponse) are sent as:

    • HTTP POST to /.well-known/auth, with a JSON-serialized AuthMessage in the request body.

    • The server processes it, possibly returning an AuthMessage in JSON.

  2. General BRC-103 messages are carried by a normal HTTP request to any path (e.g., /api/v1/orders), but encoded within custom headers plus a raw binary “payload.”

  3. The server intercepts that request, reconstructs the “general” BRC-103 message, verifies signatures, and eventually returns a corresponding “general” BRC-103 response.

This layering effectively merges the BRC-103 handshake and certificate logic with standard HTTP request/response cycles.

6. Detailed Specification

6.1 HTTP Endpoints

MUST define at least one endpoint:

  • POST /.well-known/auth

    • Accepts a JSON body representing a BRC-103 AuthMessage (any non-general type).

    • The server verifies the BRC-103 signature. On success, it MAY respond with another non-general BRC-103 message as JSON (e.g. initialResponse or certificateResponse).

    • If the handshake is incomplete or invalid, the server responds with an HTTP 4xx.

Other resource endpoints (e.g. /myapp/orders) MAY handle general messages. The request body is an ordinary HTTP request body, while key BRC-103 fields (signature, identityKey, etc.) are placed in custom headers and an encoded “payload.”

6.2 Header Conventions

BRC-104 introduces the following headers:

  1. x-bsv-auth-version: The BRC-103 version string (e.g. "1.0").

  2. x-bsv-auth-identity-key: The sender’s public identity key (33-byte compressed secp256k1 pubkey, typically hex).

  3. x-bsv-auth-nonce & x-bsv-auth-your-nonce: 32-byte ephemeral nonces used in BRC-103’s handshake.

  4. x-bsv-auth-signature: ECDSA signature in hex, verifying the message.

  5. x-bsv-auth-request-id: A client-generated 32-byte random ID (base64) to correlate request/response pairs in “general” messages.

  6. x-bsv-auth-message-type: (Optional) The BRC-103 message type if returning a certificateRequest or certificateResponse via HTTP.

  7. x-bsv-auth-requested-certificates: (Optional) JSON-encoded RequestedCertificateSet for certificate requests.

x-bsv-auth- headers MUST be excluded from the set of user-signed headers. They are ephemeral parameters or are used for BRC-103 signature itself.

6.3 Signed Fields & Excluded Fields

When building a “general” message, the BRC-103 specification requires a signature across certain fields. In BRC-104:

  • Included in signature:

    • Request method (GET, POST, etc.).

    • Request path and query string.

    • “Whitelisted” headers only:

      • authorization (client and server)

      • content-type (client-only)

      • Any header with prefix x-bsv- except x-bsv-auth-...

    • Request body bytes.

  • Excluded:

    • Non-whitelisted headers (like x-bsv-auth-*, accept)

    • Cookies, user-agent, etc.

Servers do not sign content-type because certain server middleware tends to modify the content-type header. For example, express appends charset=utf-8 to the content-type resulting in ambiguity over the pre-image being signed.

Clients however do not generally modify the content-type header in requests which allows it to be included in the pre-image being signed.

The order of included headers will be lexicographical to ensure matching preimages on both sides.

6.4 Request/Response Flow for “General” Messages

Client perspective:

  1. Construct an HTTP request as usual, but store the entire method, path, query, selected headers, and body inside a “payload” field in the BRC-103 general message.

  2. The BRC-103 identity key, version, nonce, etc., go into x-bsv-auth-* headers.

  3. Send the request over standard HTTP.

  4. The server verifies authenticity, processes the request, and returns a BRC-103 “general” message in the response:

    • The server includes x-bsv-auth-version, x-bsv-auth-signature, x-bsv-auth-identity-key, etc.

    • The actual response status code, headers, and body are re-encoded as a “payload.”

Server perspective:

  1. On receiving the request, parse the x-bsv-auth-* headers (nonce, signature, identityKey, etc.).

  2. Construct the “general” BRC-103 message from the payload.

  3. If signature checks pass, handle the HTTP request in memory (similar to a normal route).

  4. Instead of sending the result directly to the wire, embed your final status code, headers, and body in a new “general” BRC-103 message.

  5. Write it back in x-bsv-auth-* headers + the binary payload within the same HTTP response.

6.5 Request/Response Flow for “Non-General” Messages

Non-general BRC-103 messages—like initialRequest, initialResponse, certificateRequest, certificateResponseMUST be exchanged via:

  1. POST /.well-known/auth, with a JSON body:

    {
      "version": "1.0",
      "messageType": "initialRequest",
      "identityKey": "...",
      "initialNonce": "...",
      "signature": "...",
      ...
    }
  2. The server decodes the AuthMessage, verifies it, and possibly replies with another AuthMessage in JSON form:

    {
      "version": "1.0",
      "messageType": "initialResponse",
      "identityKey": "...",
      "nonce": "...",
      "yourNonce": "...",
      "signature": "...",
      ...
    }
  3. On success, the client merges that result into the BRC-103 session state.

6.6 Authentication Failure Handling

  • If the handshake or signature fails, the server MUST return 401 Unauthorized (or another 4xx suitable code) with a JSON body describing the error.

  • If the user sets invalid data, the server MAY respond with 400 Bad Request.

6.7 General Message Encoding Rules

When sending a “general” message:

6.7.1 Path Encoding Rules

  • If the path has a value, it must be serialized as UTF-8 bytes with a length prefix.

  • If the path is empty, it must default to /, serialized as UTF-8 bytes with a length prefix.

6.7.2 Query Parameter Encoding Rules

  • If query parameters are present, the entire query string (including the leading ?) must be serialized as UTF-8 bytes with a length prefix.

  • If no query parameters are present, specify a length of -1 in the payload.

6.7.3 Body Encoding Rules

The body is included raw in the BRC-103 payload, but only after a length prefix.

a. If the content-type is application/json:

  • The JSON object must be stringified and converted to UTF-8 bytes.

  • If the body is empty, an empty JSON object {} should be stringified and converted to UTF-8 bytes.

b. If the body consists of binary data (e.g. images):

  • The binary is included directly as bytes.

  • If the body is empty, specify a length of -1 in the payload.

The same rules apply to the server’s response body in a “general” response message.

6.8 Signature Preimage Calculation for HTTP Request Messages

BRC-103 specifies that the preimage is constructed by concatenating these fields in a fixed order:

  1. x-bsv-auth-request-id (32 bytes, base64-decoded).

  2. Request method: length + UTF-8 bytes.

  3. Path: length + UTF-8 bytes (use / if the path is empty).

  4. Query string (including ?): length + UTF-8 bytes (or -1 if none).

  5. Included headers: count them in the order they are transmitted. For each header:

    • VarInt of key length, followed by key bytes

    • VarInt of value length, followed by value bytes

  6. Body: length + body bytes (or -1 if none).

Finally, sign the preimage using the identity key. The server reconstructs the same preimage from the request data and verifies the signature contained in x-bsv-auth-signature.

6.9 Signature Preimage Calculation for HTTP Response Messages

In response to client request the server creates a BRC-103 payload as follows:

  1. x-bsv-auth-request-id (echoing back the client's requestId as seen on line 174).

  2. Response status (varInt)

  3. Included headers count, given in order of transmittal over the wire. For each header:

    • VarInt of key length, key bytes

    • VarInt of value length, value bytes

  4. Body length + body bytes (or -1 if none).

7. Implementation Notes & Examples

7.1 Client-Side Example

A reference “client” does the following:

  • When sending a non-general message (e.g. handshake, certificate request), it:

    1. Performs POST /.well-known/auth with Content-Type: application/json.

    2. Embeds the entire AuthMessage (BRC-103 structure) in JSON.

  • When sending a general message:

    1. Serializes method, path, query, whitelisted headers, and body into a BRC-103 payload.

    2. Supplies x-bsv-auth-version, x-bsv-auth-identity-key, x-bsv-auth-nonce, x-bsv-auth-your-nonce (if applicable), x-bsv-auth-signature, and x-bsv-auth-request-id in the request headers.

    3. On receiving the server’s HTTP response, decodes those same fields from the response headers, building a BRC-103 message that includes the returned status code, headers, and body as a “payload.”

7.2 Server-Side Example

  1. Intercept POST /.well-known/auth requests, parse them as JSON, treat them as BRC-103 “non-general.”

  2. For other paths, it checks for x-bsv-auth-request-id to see if it’s a “general” message.

  3. It re-routes the normal Express request logic so that instead of returning data directly, the server packs the data into a BRC-103 “general” message and responds accordingly.

This approach ensures a typical server can remain mostly unmodified, while the middleware handles the signature verification and re-encoding of the final response.

8. Security Considerations

  • Replay Attacks: The nonce fields in BRC-103 ensure freshness. Servers MUST reject repeated nonces.

  • Header Injection: Only a fixed set of headers is signed. If malicious headers are injected, they are outside the signature scope. Implementers should sanitize or ignore unknown headers.

  • Transport Encryption: BRC-104 does not replace TLS. Implementers SHOULD still use HTTPS to hide private or sensitive information from eavesdroppers.

  • Certificate Revocation: If identity certificates are used, the logic for checking revocationOutpoints remains as in BRC-103.

References

  • BRC-103: Peer-to-Peer Mutual Authentication and Certificate Exchange Protocol (provides handshake and message definitions).

Last updated

Was this helpful?