- Ty Everett ([email protected])
- Brayden Langley ([email protected])
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.
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.
- 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.
- BRC-103 Message: One of
initialRequest
,initialResponse
,certificateRequest
,certificateResponse
, orgeneral
. - Non-General Message: A BRC-103 message of type
initialRequest
,initialResponse
,certificateRequest
, orcertificateResponse
. - 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 aPOST
body.
- 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.
- HTTP POST to
- 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.” - 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.
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
orcertificateResponse
). - 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.”
BRC-104 introduces the following headers:
x-bsv-auth-version
: The BRC-103 version string (e.g."1.0"
).x-bsv-auth-identity-key
: The sender’s public identity key (33-byte compressed secp256k1 pubkey, typically hex).x-bsv-auth-nonce
&x-bsv-auth-your-nonce
: 32-byte ephemeral nonces used in BRC-103’s handshake.x-bsv-auth-signature
: ECDSA signature in hex, verifying the message.x-bsv-auth-request-id
: A client-generated 32-byte random ID (base64) to correlate request/response pairs in “general” messages.x-bsv-auth-message-type
: (Optional) The BRC-103 message type if returning a certificateRequest or certificateResponse via HTTP.x-bsv-auth-requested-certificates
: (Optional) JSON-encodedRequestedCertificateSet
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.
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-
exceptx-bsv-auth-...
- Request body bytes.
- Request method (
-
Excluded:
- Non-whitelisted headers (like
x-bsv-auth-*
,accept
) - Cookies, user-agent, etc.
- Non-whitelisted headers (like
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.
Client perspective:
- 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.
- The BRC-103 identity key, version, nonce, etc., go into
x-bsv-auth-*
headers. - Send the request over standard HTTP.
- 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.”
- The server includes
Server perspective:
- On receiving the request, parse the
x-bsv-auth-*
headers (nonce, signature, identityKey, etc.). - Construct the “general” BRC-103 message from the payload.
- If signature checks pass, handle the HTTP request in memory (similar to a normal route).
- Instead of sending the result directly to the wire, embed your final status code, headers, and body in a new “general” BRC-103 message.
- Write it back in
x-bsv-auth-*
headers + the binary payload within the same HTTP response.
Non-general BRC-103 messages—like initialRequest
, initialResponse
, certificateRequest
, certificateResponse
—MUST be exchanged via:
POST /.well-known/auth
, with a JSON body:{ "version": "1.0", "messageType": "initialRequest", "identityKey": "...", "initialNonce": "...", "signature": "...", ... }
- 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": "...", ... }
- On success, the client merges that result into the BRC-103 session state.
- 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
.
When sending a “general” message:
- The body is included raw in the BRC-103 payload, but only after a length prefix.
- If
content-type
isapplication/json
, you typically convert your JSON object to UTF-8 bytes. - If it is binary data (e.g. images), you pass the binary as bytes.
- If no body, specify a
-1
length in the payload.
The same approach is used for the server’s return body in the “general” response message.
The code references BRC-103’s standard approach: concatenating these fields in a stable order:
x-bsv-auth-request-id
(32 bytes, base64-decoded).- Request
method
length + UTF-8 bytes. - Path length + UTF-8 bytes (or
-1
if empty). - Query string length + UTF-8 bytes (or
-1
if none). - 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
- Body length + body bytes (or
-1
if none).
Then sign with the identity key. The server reconstructs that same preimage from the request data, verifying the signature in x-bsv-auth-signature
.
In response to client request the server creates a BRC-103 payload as follows:
x-bsv-auth-request-id
(echoing back the client's requestId as seen on line 174).- Response status (varInt)
- 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
- Body length + body bytes (or
-1
if none).
A reference “client” does the following:
- When sending a non-general message (e.g. handshake, certificate request), it:
- Performs
POST /.well-known/auth
withContent-Type: application/json
. - Embeds the entire AuthMessage (BRC-103 structure) in JSON.
- Performs
- When sending a general message:
- Serializes method, path, query, whitelisted headers, and body into a BRC-103 payload.
- 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
, andx-bsv-auth-request-id
in the request headers. - 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.”
- Intercept
POST /.well-known/auth
requests, parse them as JSON, treat them as BRC-103 “non-general.” - For other paths, it checks for
x-bsv-auth-request-id
to see if it’s a “general” message. - 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.
- 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.
- BRC-103: Peer-to-Peer Mutual Authentication and Certificate Exchange Protocol (provides handshake and message definitions).