L402 (Lightning HTTP 402)

July 9, 2026 ยท View on GitHub

Last modified: 2026-07-09

L402 support is a design direction, and none of it ships in the current binary. There is no macaroon primitive, no L402 issuer or verifier, and no invoice-provider seam anywhere in the codebase today. This page records the protocol shape SBproxy would implement so the wire format is agreed before any code lands. For the 402 payment surface that does ship, see 402-challenge.md and ai-crawl-control.md.

Why L402

The Lightning Labs L402 protocol pairs an HTTP 402 challenge with a macaroon bearer credential and a Lightning invoice. A proxy that speaks it can sit in front of paywalled HTTP resources as a drop-in alternative to aperture. The rest of this page explains the protocol; treat every "would" below literally.

Wire shape

Initial challenge:

HTTP/1.1 402 Payment Required
WWW-Authenticate: L402 macaroon="<base64url>", invoice="lnbc..."

Client retry after paying the invoice and receiving the preimage:

GET /resource HTTP/1.1
Authorization: L402 <macaroon>:<preimage_hex>

A verifier would:

  1. Parse the Authorization header into (macaroon, preimage).
  2. Recompute the macaroon HMAC chain from the root key.
  3. Check the macaroon's payment_hash=<hex> caveat against SHA-256(preimage) so a stolen macaroon does not unlock the resource without the matching preimage.
  4. Run an operator-supplied predicate over the remaining caveats (valid_until, route, audience, etc.).

The first three checks are stateless: the verifier only needs the root key, no session table.

Macaroons in one paragraph

A macaroon is an HMAC-chained bearer credential. The issuer signs (root_key, identifier) to produce sig_0; every subsequent caveat extends the chain as sig_{i+1} = HMAC(sig_i, caveat_i). The verifier replays the chain from the root key and confirms the final signature matches. Because the chain is one-way, any holder can mint a narrower macaroon by appending a caveat and extending the signature without knowing the root key. The L402 flow uses one issuer-side caveat (payment_hash) and any number of operator-defined caveats; a buyer can attenuate further before delegating to a sub-agent.

Caveats

Operator-defined caveats are opaque byte strings to the verifier; the predicate decides whether each is satisfied at request time. Common shapes:

CaveatPredicate
payment_hash=<hex>the verifier owns this one; checks SHA-256(preimage) == hex
valid_until=<unix>reject when now > unix
route=<glob>match the request path against the glob
audience=<id>match an authenticated caller id
scope=<token>gate per-route capability

Attenuation

A buyer who already paid for a macaroon can mint a narrower version for a sub-agent by appending a caveat and re-extending the signature chain. The sub-agent presents the same payment_hash preimage on the retry; the verifier's predicate sees the appended caveat and applies the operator's rule. This is how L402 supports delegation without re-paying.

Open design questions

Invoice issuance would sit behind a pluggable seam so the same code could drive an LND, CLN, or Phoenixd backend, with a static stub for local development. Where the verifier plugs into the request pipeline, and how the root key is provisioned and rotated, are unresolved. None of these seams exist yet.

See also