> For the complete documentation index, see [llms.txt](https://bsv.brc.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://bsv.brc.dev/wallet/0154.md).

# Pluggable Backup Services for BRC-140 Share Vaults

Brandon Cryderman / HandCash (<brandongcryderman@gmail.com>)

## Abstract

This BRC defines an HTTP **backup service** profile for optional recovery of [BRC-140](/key-derivation/0140.md) key shares. A backup service stores **at most one** BRC-140 share per authenticated account and releases it only after authentication. Wallets may enroll a **list** of independent service URLs, deposit distinct shares across them under a threshold scheme, and reconstruct the key locally after obtaining enough shares.

A backup service MUST NOT be required for ordinary wallet operation under [BRC-100](/wallet/0100.md). It MUST NOT receive the root private key, and a conforming wallet MUST NOT send enough shares to any single service to meet the wallet’s recovery threshold.

## Motivation

[BRC-140](/key-derivation/0140.md) specifies threshold key sharing and the canonical share serialization. It does not define how optional network providers store and release those shares. Without a shared service profile, wallets invent incompatible recovery APIs and users concentrate recovery on a single operator.

This BRC specifies a minimal, pluggable wire contract so any operator can run a share vault and any wallet can enroll multiple providers interchangeably. Cryptography remains BRC-140; this document covers discovery metadata, authentication for release, share endpoints, and operator lifecycle signaling.

## Specification

### Terminology

| Term               | Meaning                                                                                         |
| ------------------ | ----------------------------------------------------------------------------------------------- |
| **Backup service** | HTTP origin that stores ≤ 1 BRC-140 share per authenticated account and releases it after auth. |
| **Wallet**         | Client that splits/reconstructs keys per BRC-140 and speaks this profile.                       |
| **Enrollment**     | Successful deposit of exactly one share to one backup service for one authenticated account.    |
| **Recovery**       | Obtaining ≥ threshold distinct shares and reconstructing the key in the wallet.                 |

### Relationship to other BRCs

| Standard                                                                                   | Role                                                                                    |
| ------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------- |
| [BRC-140](/key-derivation/0140.md)                                                         | Share math and `x.y.threshold.integrity` serialization (normative for `share` payloads) |
| [BRC-75](/key-derivation/0075.md)                                                          | Offline mnemonic recovery; complementary and out of scope                               |
| [BRC-38](/outpoints/0038.md) / [BRC-39](/outpoints/0039.md) / [BRC-40](/outpoints/0040.md) | Wallet *data* export/sync; out of scope                                                 |
| [BRC-100](/wallet/0100.md)                                                                 | App↔wallet interface; MUST remain usable with zero backup services configured           |

### Non-goals

* Threshold signatures or spend-time co-signing.
* Requiring backup services for send, receive, or BRC-100 connect.
* A global registry of providers.
* Wallet UTXO / history synchronization.
* Mandating a particular identity or KYC regime.

### Cryptographic model

1. The wallet splits its root private key with BRC-140.
2. The wallet deposits **at most one share per backup service**.
3. Reconstruction happens only in the wallet after enough shares are obtained.
4. Services MUST NEVER receive the reconstructed key.

**Invariant (service):** store at most one share per authenticated account; reject non-BRC-140 share strings.

**Invariant (wallet):** MUST NOT send the root private key, mnemonic, or ≥ threshold shares from one split to any single backup service.

A common enrollment scheme is threshold 2 of 3 total shares. Other thresholds are permitted if the wallet and user agree on the scheme before deposit.

### Account binding

The bearer session returned by authentication MUST be bound to a provider-local account. Share endpoints operate on that authenticated account and MUST NOT accept a caller-supplied email, handle, public key, or account hash to select another account's share.

The provider MAY use any internal account identifier. That identifier is not part of this wire profile and MUST NOT be treated as an anonymity mechanism: a provider can associate the stored share with the identity presented during authentication.

### HTTP profile

Base URL is an HTTPS origin (loopback HTTP MAY be used for development). Paths are relative to that origin. JSON UTF-8 bodies. Unknown JSON fields MUST be ignored.

#### `GET /info`

No auth required.

```json
{
  "name": "Example Backup",
  "version": "0.1.0",
  "role": "backup-service",
  "authMethods": ["com.example.connect", "webauthn", "email-otp"],
  "lifecycle": {
    "status": "active",
    "sunsetAt": null,
    "retireAt": null,
    "message": null,
    "successorUrl": null
  }
}
```

| Field         | Requirement | Meaning                                                        |
| ------------- | ----------- | -------------------------------------------------------------- |
| `name`        | MUST        | Operator display name                                          |
| `version`     | SHOULD      | Operator software version                                      |
| `role`        | SHOULD      | Constant `backup-service`                                      |
| `authMethods` | MUST        | Non-empty array of supported authentication method identifiers |
| `lifecycle`   | MUST        | Operator lifecycle block                                       |

#### Lifecycle

| `lifecycle.status` | Meaning                                        |
| ------------------ | ---------------------------------------------- |
| `active`           | Enroll and retrieve allowed                    |
| `sunset`           | Retrieve allowed; new enrolls MUST be rejected |
| `retired`          | Retrieve MUST fail                             |

| Field          | Requirement            | Meaning                                    |
| -------------- | ---------------------- | ------------------------------------------ |
| `sunsetAt`     | MAY                    | RFC 3339 UTC                               |
| `retireAt`     | SHOULD when sunsetting | Last expected retrieve time (RFC 3339 UTC) |
| `message`      | MAY                    | Operator explanation                       |
| `successorUrl` | MAY                    | Suggested replacement base URL             |

Wallets SHOULD refresh `/info` for enrolled URLs and stop new enrolls when status is not `active`. Operators SHOULD provide a sunset window before `retireAt`.

#### Authentication

Authentication is capability-negotiated. This BRC defines a common start/complete envelope but does not mandate a specific identity provider or factor.

`authMethods` contains identifiers for authentication profiles understood by the service. Provider-specific identifiers SHOULD use reverse-domain form (for example `com.example.connect`). Existing standardized identifiers such as `webauthn` MAY be used directly. Email OTP, redirect-based Connect providers, passkeys, and challenge-response systems are all possible profiles; none is required by this BRC. Wallets MUST ignore methods they do not implement.

An authentication method used for recovery MUST remain usable without possession of the secret being recovered. A signature key derived only from the BRC-140-protected root key MUST NOT be the sole recovery method, because that creates a circular dependency. Redirect or challenge methods are conforming only when their credential can be recovered independently.

**`POST /auth/start`**

```json
{
  "method": "com.example.connect",
  "params": {}
}
```

Response (`200`):

```json
{
  "requestId": "<opaque>",
  "expiresInSec": 600,
  "action": {
    "type": "redirect",
    "url": "https://identity.example/authorize?request=<opaque>"
  }
}
```

`params` and `action` are method-specific objects. Defined `action.type` values are:

* `redirect` — open `action.url`; the authorization result is supplied to `/auth/complete`.
* `challenge` — produce a proof over `action.challenge`.
* `outOfBand` — complete the externally delivered challenge (such as an OTP).

Unknown action fields MUST be ignored.

**`POST /auth/complete`**

```json
{
  "requestId": "<opaque>",
  "response": {}
}
```

Response (`200`):

```json
{
  "token": "<bearer secret>",
  "expiresInSec": 1800
}
```

`response` is method-specific. The service MUST validate that it completes the referenced request and MUST bind the returned bearer token to the authenticated provider-local account.

Share endpoints use `Authorization: Bearer <token>`. Tokens SHOULD be short-lived and scoped to backup-service operations.

#### Share endpoints

All share endpoints require a valid bearer session.

```json
{
  "share": "<BRC-140 backup string>"
}
```

(`share` only where noted.)

**`POST /share/enroll`**

* MUST validate `share` as BRC-140 backup serialization.
* MUST fail with `403` when lifecycle forbids enroll.
* Stores exactly one share for the authenticated account (overwrite policy is operator-defined; `/share/rotate` SHOULD be preferred for explicit replacement).

Response (`200`):

```json
{ "ok": true, "enrolledAt": "<RFC 3339>" }
```

**`POST /share/retrieve`**

Request: `{}`.

Response (`200`):

```json
{ "share": "<BRC-140 backup string>", "enrolledAt": "<RFC 3339>" }
```

* MUST NOT return a share without successful auth under the service’s policy.
* MUST fail when lifecycle is `retired` or past `retireAt`.
* MUST `404` when no share is stored.

**`POST /share/rotate` (SHOULD)**

Replace the stored share after auth. Same validation as enroll.

**`POST /share/delete`**

Request: `{}`. Idempotent; response `{ "ok": true }`.

### Wallet requirements

1. Support a list of backup-service base URLs; an empty list MUST be valid.
2. Ordinary spend / BRC-100 use MUST NOT depend on any backup service.
3. Deposit at most one share from a given split to a given service origin.
4. Reconstruct only locally.
5. Keep offline BRC-140 and/or BRC-75 recovery available without services.

### Security considerations

| Risk                       | Mitigation                                                                                                               |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Single service compromised | Threshold ≥ 2; one share insufficient                                                                                    |
| Colluding services         | Threshold and enrollment topology determine exposure; wallets MUST NOT send ≥ threshold shares to one party              |
| Authentication compromise  | Short-lived scoped tokens, rate limiting, and operator-appropriate factors                                               |
| Circular recovery auth     | A key derived solely from the protected root MUST NOT be the only release credential                                     |
| Identity↔share linkage     | The provider can associate its authenticated account with the share; treat providers as share custodians for that record |
| Operator disappearance     | Multi-provider enrollment and offline BRC-140 / BRC-75                                                                   |
| Malformed shares           | Reject non-BRC-140; verify integrity at reconstruct                                                                      |

Protect share transport with TLS. Minimize logging of share material. Encrypt shares at rest under an operator key that is not the user’s root key.

## Implementations

HandCash Desktop and its `backup-service` prototype implement multi-provider BRC-140 share storage on branch `feat/backup-services`. The prototype's original email-OTP exchange predates the capability-negotiated authentication envelope in this draft and is not presented as a complete conforming implementation.

## References

* 1: [BRC-140 — Threshold Key Sharing and Backup via Shamir's Secret Sharing Scheme](/key-derivation/0140.md)
* 2: [BRC-100 — Unified Wallet-to-Application Interface](/wallet/0100.md)
* 3: <https://github.com/HandCash/HANDCASH-DESKTOP> (branch `feat/backup-services`)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://bsv.brc.dev/wallet/0154.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
