diff --git a/README.md b/README.md index 31bae19..4b043d2 100644 --- a/README.md +++ b/README.md @@ -3,27 +3,27 @@ L402 is an open protocol for paying for and authenticating access to APIs and services over the internet using the Lightning Network. Developed by [Lightning Labs](https://lightning.engineering/), it brings to life the -long-dormant HTTP `402 Payment Required` status code by combining macaroons -(cryptographic bearer credentials) with Lightning Network micropayments. +long-dormant HTTP `402 Payment Required` status code by combining cryptographic +authentication tokens with Lightning Network micropayments. ## How It Works 1. A client requests a paid resource from a server. 2. The server responds with `402 Payment Required`, including an authentication - macaroon and a Lightning invoice in the `WWW-Authenticate` header. + token and a Lightning invoice in the `WWW-Authenticate` header. 3. The client pays the invoice over Lightning, receiving a payment preimage as proof of payment. -4. The client re-sends the request with the macaroon and preimage in the +4. The client re-sends the request with the token and preimage in the `Authorization` header. 5. The server verifies the credential and serves the resource. -The macaroon cryptographically commits to the payment hash of the invoice, so -the server can verify payment using only the macaroon and preimage. No database -lookups or session state required. +The token cryptographically commits to the payment hash of the invoice, so the +server can verify payment using only the token and preimage. No database lookups +or session state required. ``` -WWW-Authenticate: L402 macaroon="", invoice="" -Authorization: L402 : +WWW-Authenticate: L402 version="0", token="", invoice="" +Authorization: L402 : ``` ## Why L402? @@ -36,12 +36,13 @@ collected. subscriptions, users pay for exactly what they use. A single API call can cost fractions of a cent. -**Programmable credentials.** Macaroons support attenuation: a credential -holder can create a weaker version of their credential to share with others, -restricting access to specific services, capabilities, or usage limits. +**Programmable credentials.** When using macaroons as the token format (the +recommended default), credentials support attenuation: a token holder can create +a weaker version of their credential to share with others, restricting access to +specific services, capabilities, or usage limits. -**Stateless verification.** Servers verify credentials using only the macaroon -and preimage, no centralized database needed. This makes L402 a natural fit for +**Stateless verification.** Servers verify credentials using only the token and +preimage, no centralized database needed. This makes L402 a natural fit for distributed systems and microservice architectures. ## Agents and Agentic Commerce @@ -59,6 +60,35 @@ human in the loop. As agents increasingly transact with services (and each other) using real money, L402 provides the payment+authentication layer to make that work over open payment rails. +## Token Format + +L402 is token-format agnostic: any token that commits to a payment hash works. +[Macaroons](docs/macaroons.md) (HMAC-chain bearer credentials) are the +recommended format because they support delegation and attenuation through +caveats, stateless verification via HMAC chains, and service-level access +control with tier encoding. See the +[Macaroon Minting & Verification](docs/macaroons.md) chapter and the +[Macaroon Technical Specification](macaroon-spec.md) for the full details. + +## What's New + +This revision of the L402 specification aligns with +[bLIP-0026](https://github.com/lightning/blips/blob/master/blip-0026.md) and +includes the following updates: + +- **Token generalization.** The protocol is now token-format agnostic. The + `WWW-Authenticate` header uses `token=` instead of the former `macaroon=`. + Macaroons remain the recommended format. +- **Version system.** A `version="0"` parameter is now included in the + `WWW-Authenticate` challenge header, enabling future protocol evolution. +- **Backwards compatibility.** Explicit rules for accepting both `L402`/`LSAT` + scheme names and `token=`/`macaroon=` parameter names. +- **Security guidance.** Expanded security considerations covering caveat-based + token binding (IP, TLS fingerprint, origin domain). +- **Agent specification.** A new [agent-spec.md](agent-spec.md) provides the + complete protocol in ~560 tokens (~420 words), designed for AI agent context + windows. + ## Specification * [Protocol Specification](protocol-specification.md): HTTP and gRPC protocol details, formal definitions @@ -76,9 +106,11 @@ that work over open payment rails. * [Aperture](https://github.com/lightninglabs/aperture): gRPC/HTTP authentication reverse proxy using L402 * [lsat-js](https://github.com/Tierion/lsat-js): JavaScript utility library for working with L402 credentials * [boltwall](https://github.com/tierion/boltwall): Node.js middleware-based authentication using L402 +* [Fewsats](https://www.fewsats.com/): L402-compatible API marketplace and CLI tools ## External Links * [Builder's Guide Documentation](https://docs.lightning.engineering/the-lightning-network/l402) * [Macaroons: Cookies with Contextual Caveats (Google Research)](https://research.google/pubs/pub41892/) * [HTTP/1.1 RFC, Section 6.5.2: 402 Payment Required](https://tools.ietf.org/html/rfc7231#section-6.5.2) +* [bLIP-0026: L402 Protocol Specification](https://github.com/lightning/blips/blob/master/blip-0026.md) diff --git a/agent-spec.md b/agent-spec.md index 703a501..25a4e6a 100644 --- a/agent-spec.md +++ b/agent-spec.md @@ -1,41 +1,47 @@ # L402 Agent Specification -Token-efficient reference for L402 protocol integration. +Token-efficient reference for L402 protocol integration. Version 0. ## Core Concept -L402 = HTTP 402 + Lightning invoice + macaroon. Client pays invoice, gets -preimage, presents `(macaroon, preimage)` to authenticate. Stateless -verification: macaroon commits to payment hash H, server checks -`H == sha256(preimage)`. +L402 = HTTP 402 + Lightning invoice + auth token. Client pays invoice, gets +preimage, presents `(token, preimage)` to authenticate. Stateless verification: +token commits to payment hash H, server checks `H == sha256(preimage)`. ## Headers **Challenge** (server → client): ``` HTTP/1.1 402 Payment Required -WWW-Authenticate: L402 macaroon="", invoice="" +WWW-Authenticate: L402 version="0", token="", invoice="" ``` **Authorization** (client → server): ``` -Authorization: L402 : +Authorization: L402 : ``` -Multiple macaroons: comma-separate base64 values before the colon. +Multiple tokens: comma-separate base64 values before the colon. ## Protocol Flow ``` Client → Server: GET /resource -Server → Client: 402 + WWW-Authenticate: L402 macaroon="M", invoice="P" +Server → Client: 402 + WWW-Authenticate: L402 version="0", token="T", invoice="P" Client → LN: pay(P) → preimage r -Client → Server: GET /resource + Authorization: L402 M:r -Server: verify H == sha256(r), verify macaroon integrity +Client → Server: GET /resource + Authorization: L402 T:r +Server: verify H == sha256(r), verify token integrity Server → Client: 200 OK + resource ``` -## Macaroon Identifier +## Token Requirements + +- MUST commit to payment hash H of invoice P +- MUST be verifiable without backend state (stateless) +- RECOMMENDED format: macaroons (HMAC chain, supports caveats/attenuation) +- MAY use any format satisfying above constraints + +## Macaroon Identifier (when using macaroons) Big-endian encoding: @@ -43,7 +49,7 @@ Big-endian encoding: |-------|------|-------------| | version | 2 bytes | uint16, currently 0 | | payment_hash | 32 bytes | sha256 hash from invoice | -| token_id | 32 bytes | random, tracks user across macaroon rotations | +| token_id | 32 bytes | random, tracks user across token rotations | ## Caveats (macaroon attenuation) @@ -59,30 +65,33 @@ Each additional caveat of same key MUST restrict further (never widen). Same auth scheme. Differences: - Server MUST return HTTP 200 (gRPC requirement) -- Challenge encoded in `grpc-status-details-bin` as serialized gRPC Status proto -- Client sends macaroon as `Custom-Metadata` key "macaroon" +- Add trailers: `Grpc-Message: payment required`, `Grpc-Status: 13` +- Client sends token as `Custom-Metadata` key "token" ## Backwards Compatibility - Accept `LSAT` anywhere `L402` appears +- Accept `macaroon=` in addition to `token=` in headers +- Accept missing `version` parameter (pre-versioning clients) ## Credential Lifecycle - Reuse until revoked (expiry, usage limit, tier upgrade) -- Revoke by deleting root key -- Upgrade: revoke old macaroon, mint new with expanded capabilities +- Revoke by deleting root key (macaroons) or invalidating token +- Upgrade: revoke old token, mint new with expanded capabilities ## Implementation Checklist Server: -1. Mint macaroon committing to payment hash -2. Return 402 + WWW-Authenticate with macaroon, invoice -3. On auth request: verify macaroon integrity, check `H == sha256(r)` +1. Mint token committing to payment hash +2. Return 402 + WWW-Authenticate with version, token, invoice +3. On auth request: verify token integrity, check `H == sha256(r)` 4. Accept both `L402` and `LSAT` scheme names +5. Accept both `token=` and `macaroon=` parameter names Client: -1. Parse WWW-Authenticate, extract macaroon + invoice +1. Parse WWW-Authenticate, extract token + invoice 2. Validate invoice amount is acceptable 3. Pay invoice, obtain preimage -4. Send `Authorization: L402 :` +4. Send `Authorization: L402 :` 5. Cache credential for reuse diff --git a/docs/authentication-flow.md b/docs/authentication-flow.md index 3675d4d..bece270 100644 --- a/docs/authentication-flow.md +++ b/docs/authentication-flow.md @@ -36,19 +36,19 @@ sequenceDiagram A->>A: Check credential, none found A->>AL: Generate invoice AL-->>A: Invoice P - A->>A: Mint macaroon M (commits to H) - A-->>C: 402 Payment Required + WWW-Authenticate: L402 macaroon="M", invoice="P" + A->>A: Create token T (commits to H) + A-->>C: 402 Payment Required + WWW-Authenticate: L402 version="0", token="M", invoice="P" C->>CL: Pay invoice P CL->>AL: Pay invoice (LN payment) AL-->>CL: Preimage r CL-->>C: Preimage r - C->>C: Store macaroon M + preimage r + C->>C: Store token T + preimage r end rect rgb(240, 255, 240) Note over C,R: User with credential C->>A: GET /protected + Authorization: L402 M:r - A->>A: Verify macaroon, check H == sha256(r) + A->>A: Verify token, check H == sha256(r) A->>R: GET /protected (forwarded) R-->>A: Protected content A-->>C: 200 OK + Protected content @@ -73,30 +73,30 @@ authentication server. 3. The proxy instructs its backing Lightning node to create an invoice over the small amount required to acquire a fresh credential. -4. In addition to the invoice, the proxy mints a fresh macaroon tied to the - invoice. The macaroon is cryptographically constructed so that it is only - valid once the invoice has been paid (the macaroon identifier commits to the +4. In addition to the invoice, the proxy creates a fresh authentication token + tied to the invoice. The token is cryptographically constructed so that it + is only valid once the invoice has been paid (the token commits to the invoice's payment hash). -5. The macaroon and invoice are sent back to the client via the +5. The token and invoice are sent back to the client via the `WWW-Authenticate` header alongside the HTTP 402 status code: ``` - WWW-Authenticate: L402 macaroon="", invoice="" + WWW-Authenticate: L402 version="0", token="", invoice="" ``` 6. The client extracts the invoice and automatically instructs its connected Lightning node to pay it. 7. Paying the invoice reveals the cryptographic proof of payment (the - preimage). The client stores the preimage alongside the macaroon. + preimage). The client stores the preimage alongside the token. -8. The combination of the macaroon and preimage yields a fully valid L402 +8. The combination of the token and preimage yields a fully valid L402 credential that can be cryptographically verified. 9. The client repeats the original request, attaching the L402 credential via the `Authorization` header: ``` - Authorization: L402 : + Authorization: L402 : ``` 10. The authentication server intercepts the request, extracts the L402, and diff --git a/docs/introduction.md b/docs/introduction.md index 7f792cb..9fa19d9 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -15,6 +15,13 @@ specification uses a combination of `HTTP` and the Lightning Network to create a seamless end-to-end payment+authentication flow for the next generation of paid APIs built on top of the Lightning Network. +The L402 protocol is token-format agnostic: any authentication token that can +commit to a payment hash may be used. Macaroons (HMAC-chain bearer credentials) +are the RECOMMENDED token format due to their support for delegation, +attenuation of capabilities, and stateless verification. See the +[Macaroon Minting & Verification](macaroons.md) chapter for full details on the +macaroon-based token format. + The system described above isn't a fantasy. L402 is used _today_ in production to serve as an authentication+payment solution for services built on the Lightning Network. The reference implementation is @@ -65,7 +72,7 @@ At this point, curious users may be wondering: How would such a scheme work? Are the payment and receipt steps atomic? Why can't a user just forge one of these "tickets"? -## HTTP + Macaroons + Lightning = L402 +## HTTP + Tokens + Lightning = L402 An L402 is essentially a ticket obtained over Lightning for a particular service or resource. The ticket itself _encodes_ what resource it's able to access. It diff --git a/docs/macaroons.md b/docs/macaroons.md index 0815946..f99d0c8 100644 --- a/docs/macaroons.md +++ b/docs/macaroons.md @@ -4,6 +4,11 @@ In this chapter, we outline the specification of the Macaroon component of a Lightning API key \(L402\). To recap, an L402 is composed of a Macaroon, which specifies the allowed capabilities of the credential, and a preimage, which serves as the credential’s proof of payment. Macaroons are perfect candidates for L402 as they are tamper-proof, support easy rotation, have attributes, and can even be further attenuated in order for applications that integrate an L402 enabled service to delegate any additional capabilities. We’ll cover how Macaroons are created, attenuated, and verified as part of L402. This chapter will require an understanding of how Macaroons work and how they are useful in the context of authentication. It may be useful to skim the [introductory research paper on Macaroons](https://research.google/pubs/pub41892/). +**Note:** The macaroon identifier structure and caveat formats described in +this chapter are RECOMMENDED conventions. Implementations MAY use alternative +token formats provided they satisfy the core L402 protocol requirements +(see [Protocol Specification](../protocol-specification.md), Section 5.3). + ## Minting Macaroons Macaroons have three basic components: a public identifier that maps to a root key, a list of caveats \(which is how attenuation is achieved\), and a signature. Minting a new Macaroon only requires the public identifier and the root key it corresponds to. diff --git a/protocol-specification.md b/protocol-specification.md index 88c0196..ddb7eff 100644 --- a/protocol-specification.md +++ b/protocol-specification.md @@ -6,16 +6,21 @@ This document specifies the L402 authentication scheme for HTTP and gRPC. L402 combines the [HTTP 402 Payment Required](https://tools.ietf.org/html/rfc7231#section-6.5.2) status code with [Lightning Network](https://github.com/lightning/bolts) invoice payments to create a challenge-response protocol for paid API access. -A server issues a _challenge_ containing an authentication credential and a +A server issues a _challenge_ containing an authentication token and a Lightning invoice; the client pays the invoice to obtain a preimage, then -presents the credential and preimage together as proof of payment. +presents the token and preimage together as proof of payment. -The credential is a [macaroon](https://research.google/pubs/pub41892/) (an -HMAC-chain bearer token) that cryptographically commits to the invoice's -payment hash. This binding enables stateless verification: the server checks -`H == sha256(preimage)` against the hash embedded in the macaroon, with no -database lookup required. See [Macaroon Minting & Verification](docs/macaroons.md) -for a full treatment of the macaroon format. +The L402 protocol is token-format agnostic: any authentication token that can +commit to a payment hash may be used. [Macaroons](https://research.google/pubs/pub41892/) +(HMAC-chain bearer credentials) are the RECOMMENDED token format due to their +support for delegation, attenuation of capabilities, and stateless +verification. See [Macaroon Minting & Verification](docs/macaroons.md) for +an overview and the [Macaroon Technical Specification](macaroon-spec.md) for +full construction details. + +The token cryptographically commits to the invoice's payment hash, enabling +stateless verification: the server checks `H == sha256(preimage)` against the +hash embedded in the token, with no database lookup required. For higher-level motivation and use cases, see the [Introduction](docs/introduction.md). @@ -31,31 +36,35 @@ appear in all capitals, as shown here. ## 3. Terminology -**L402 Credential.** A `:` pair transmitted in the HTTP -`Authorization` header. The macaroon is base64-encoded; the preimage is +**L402 Credential.** A `:` pair transmitted in the HTTP +`Authorization` header. The token is base64-encoded; the preimage is hex-encoded. This is the artifact a client presents to prove payment. -**Macaroon.** An HMAC-chain bearer credential minted by the server. The -macaroon's identifier commits to the payment hash of a Lightning invoice. -Macaroons support _caveats_ (restrictions) and _attenuation_ (delegation with -reduced authority). See the [Macaroon Technical Specification](macaroon-spec.md) -for construction details. +**Token.** An authentication credential minted by the server. The token MUST +commit to the payment hash of a Lightning invoice. Macaroons (HMAC-chain bearer +credentials) are the RECOMMENDED token format. + +**Macaroon.** An HMAC-chain bearer credential. When used as the L402 token +format, the macaroon's identifier commits to the payment hash. Macaroons +support _caveats_ (restrictions) and _attenuation_ (delegation with reduced +authority). See the [Macaroon Technical Specification](macaroon-spec.md) for +construction details. **Preimage.** The 32-byte value `r` such that `sha256(r)` equals the payment hash of the Lightning invoice. Possession of the preimage proves the invoice was paid. **Payment Hash.** The SHA-256 hash `H` of the preimage, embedded in both the -Lightning invoice and the macaroon identifier. The binding `H == sha256(r)` is -the core verification primitive. +Lightning invoice and the token. The binding `H == sha256(r)` is the core +verification primitive. **Challenge.** The `WWW-Authenticate: L402 ...` header returned by the server -alongside HTTP 402, containing a macaroon and a Lightning invoice. +alongside HTTP 402, containing a token and a Lightning invoice. **Caveat.** A restriction appended to a macaroon's HMAC chain. Caveats can encode service access, capabilities, expiration, volume limits, and other constraints. Each successive caveat can only _narrow_ the macaroon's authority, -never widen it. +never widen it. (Applicable when macaroons are the token format.) ## 4. Protocol Overview @@ -66,11 +75,11 @@ sequenceDiagram participant LN as Lightning Network C->>S: GET /resource - S-->>C: 402 Payment Required
WWW-Authenticate: L402 macaroon="M", invoice="P" + S-->>C: 402 Payment Required
WWW-Authenticate: L402 version="0", token="T", invoice="P" C->>LN: pay(P) LN-->>C: preimage r - C->>S: GET /resource
Authorization: L402 M:r - S->>S: verify macaroon, check H == sha256(r) + C->>S: GET /resource
Authorization: L402 T:r + S->>S: verify token, check H == sha256(r) S-->>C: 200 OK + resource ``` @@ -78,8 +87,8 @@ sequenceDiagram | Condition | Status | Response | |-----------|--------|----------| -| Resource requires payment, no credential provided | 402 | `WWW-Authenticate` challenge with macaroon + invoice | -| Credential present but macaroon invalid or tampered | 401 | Unauthorized | +| Resource requires payment, no credential provided | 402 | `WWW-Authenticate` challenge with token + invoice | +| Credential present but token invalid or tampered | 401 | Unauthorized | | Credential present but preimage does not match payment hash | 401 | Unauthorized | | Credential valid, access granted | 200 | Requested resource | @@ -100,14 +109,19 @@ When a server requires payment for a resource, it MUST respond with HTTP 402 and include a `WWW-Authenticate` header of the form: ``` -WWW-Authenticate: L402 macaroon="", invoice="" +WWW-Authenticate: L402 version="0", token="", invoice="" ``` **Parameters:** -- `macaroon` (REQUIRED): The authentication macaroon, base64-encoded - ([RFC 4648](https://tools.ietf.org/html/rfc4648)). The macaroon MUST commit - to the payment hash `H` of the invoice `P` in its identifier +- `version` (REQUIRED): A protocol version string. The current version is `"0"`. + Clients MUST ignore unknown key=value parameters in the challenge header, to + allow future extensions to the protocol (e.g., alternative invoice formats). + +- `token` (REQUIRED): The authentication token, base64-encoded + ([RFC 4648](https://tools.ietf.org/html/rfc4648)). The token MUST commit to + the payment hash `H` of the invoice `P`. When macaroons are used as the token + format, the payment hash is embedded in the macaroon identifier (see [Macaroon Technical Specification](macaroon-spec.md), Section "Identifier Structure"). @@ -120,12 +134,12 @@ WWW-Authenticate: L402 macaroon="", invoice="" ```text HTTP/1.1 402 Payment Required Date: Mon, 04 Feb 2014 16:50:53 GMT -WWW-Authenticate: L402 macaroon="AGIAJEemVQUTEyNCR0exk7ek90Cg==", invoice="lnbc1500n1pw5kjhmpp5fu6xhthlt2vucmzkx6c7wtlh2r625r30cyjsfqhu8rsx4xpz5lwqdpa2fjkzep6yptksct5yp5hxgrrv96hx6twvusycn3qv9jx7ur5d9hkugr5dusx6cqzpgxqr23s79ruapxc4j5uskt4htly2salw4drq979d7rcela9wz02elhypmdzmzlnxuknpgfyfm86pntt8vvkvffma5qc9n50h4mvqhngadqy3ngqjcym5a" +WWW-Authenticate: L402 version="0", token="AGIAJEemVQUTEyNCR0exk7ek90Cg==", invoice="lnbc1500n1pw5kjhmpp5fu6xhthlt2vucmzkx6c7wtlh2r625r30cyjsfqhu8rsx4xpz5lwqdpa2fjkzep6yptksct5yp5hxgrrv96hx6twvusycn3qv9jx7ur5d9hkugr5dusx6cqzpgxqr23s79ruapxc4j5uskt4htly2salw4drq979d7rcela9wz02elhypmdzmzlnxuknpgfyfm86pntt8vvkvffma5qc9n50h4mvqhngadqy3ngqjcym5a" ``` -Where `"AGIAJEemVQUTEyNCR0exk7ek90Cg=="` is the macaroon the client must -include in each authorized request, and `"lnbc1500n1pw5kjhmpp..."` is the -BOLT 11 invoice the client must pay to reveal the preimage. +Where `"AGIAJEemVQUTEyNCR0exk7ek90Cg=="` is the token the client MUST include +in each authorized request, and `"lnbc1500n1pw5kjhmpp..."` is the BOLT 11 +invoice the client must pay to reveal the preimage. ### 5.2. Credentials (Authorization) @@ -133,13 +147,13 @@ The L402 credential is transmitted in the `Authorization` header using the following syntax: ``` -Authorization: L402 : +Authorization: L402 : ``` Where: -- The macaroon is base64-encoded per [RFC 4648](https://tools.ietf.org/html/rfc4648). - Multiple macaroons are base64-encoded individually and comma-separated before +- The token is base64-encoded per [RFC 4648](https://tools.ietf.org/html/rfc4648). + Multiple tokens are base64-encoded individually and comma-separated before the colon. - The preimage is hex-encoded per [RFC 3548, Section 6](https://tools.ietf.org/html/rfc3548#section-6). @@ -153,22 +167,43 @@ HTTP Basic auth. Authorization: L402 AGIAJEemVQUTEyNCR0exk7ek90Cg==:1234abcd1234abcd1234abcd ``` -Since the macaroon and preimage are both binary data encoded in ASCII, there is +Since the token and preimage are both binary data encoded in ASCII, there is no issue with control characters or colons (see "CTL" in [Appendix B.1 of RFC 5234](https://tools.ietf.org/html/rfc5234#appendix-B.1)). -If a client provides a macaroon or preimage containing control characters, the +If a client provides a token or preimage containing control characters, the server MUST treat it as an invalid L402 and respond with 401. -### 5.3. Grammar +### 5.3. Token Format + +The L402 protocol is token-format agnostic. Any token format that satisfies +the following requirements MAY be used: + +1. The token MUST commit to the payment hash `H` of the Lightning invoice. +2. The token MUST be verifiable without per-request backend state (stateless + verification). +3. The token SHOULD support some mechanism for restricting scope or authority. + +Macaroons (HMAC-chain bearer credentials) are the RECOMMENDED token format +because they satisfy all three requirements and additionally support: + +- Delegation and attenuation through caveats +- Stateless verification via HMAC chains +- Service-level access control with tier encoding + +See the [Macaroon Technical Specification](macaroon-spec.md) for the full +details on macaroon construction, verification, and attenuation. + +### 5.4. Grammar ``` l402-challenge = "L402" 1*SP l402-params -l402-params = macaroon-param "," SP invoice-param -macaroon-param = "macaroon" "=" quoted-string +l402-params = version-param "," SP token-param "," SP invoice-param +version-param = "version" "=" quoted-string +token-param = "token" "=" quoted-string invoice-param = "invoice" "=" quoted-string -l402-credential = "L402" 1*SP macaroons ":" preimage -macaroons = base64 *("," base64) +l402-credential = "L402" 1*SP tokens ":" preimage +tokens = base64 *("," base64) preimage = 1*HEXDIG base64 = 1*( ALPHA / DIGIT / "+" / "/" / "=" ) ``` @@ -185,10 +220,10 @@ valid L402 credential: [BOLT 11](https://github.com/lightning/bolts/blob/master/11-payment-encoding.md) invoice `P` requesting that amount from its backing Lightning node. -2. The server MUST mint a new macaroon `M` for the client. The macaroon MUST - commit to the payment hash `H` of the invoice `P` in its identifier. This +2. The server MUST create a new authentication token `T` for the client. The + token MUST commit to the payment hash `H` of the invoice `P`. This commitment enables in-band payment verification: the server can confirm a - client has paid using only the macaroon and preimage, with no additional + client has paid using only the token and preimage, with no additional state or backend lookup. 3. The server MUST reply with HTTP 402 (Payment Required). Officially, the @@ -197,19 +232,21 @@ valid L402 credential: but this document assumes the future has arrived. 4. The server MUST include a `WWW-Authenticate` header per Section 5.1 - containing the macaroon and invoice. + containing the version, token, and invoice: + ``` + WWW-Authenticate: L402 version="0", token="T", invoice="P" + ``` Upon receiving a request with an `Authorization: L402` header: -1. The server MUST verify the cryptographic integrity of the macaroon (HMAC - chain verification against the root key). If the macaroon is invalid, the - server MUST return 401 Unauthorized. +1. The server MUST verify the cryptographic integrity of the token. If the + token is invalid, the server MUST return 401 Unauthorized. 2. The server MUST parse the `Authorization` header into the base64-encoded - macaroon `M` and the hex-encoded preimage `r`. + token `T` and the hex-encoded preimage `r`. -3. The server MUST verify that the invoice tied to the macaroon has been paid: - 1. If the server committed to the payment hash `H` in the macaroon, it can +3. The server MUST verify that the invoice tied to the token has been paid: + 1. If the server committed to the payment hash `H` in the token, it can verify that `H == sha256(r)`. This is the RECOMMENDED approach as it enables stateless verification. 2. Otherwise, the server SHOULD verify that the invoice `P` has been paid @@ -220,8 +257,8 @@ Upon receiving a request with an `Authorization: L402` header: It is imperative that the server ensure payment before processing the request or forwarding it to a backend. By cryptographically committing to the payment -hash in the macaroon, the server can perform fast, stateless verification of -the payment hash + preimage relation. +hash in the token, the server can perform fast, stateless verification of the +payment hash + preimage relation. ### 6.2. Client Flow @@ -236,7 +273,7 @@ Upon receiving a `WWW-Authenticate: L402` challenge: 3. The client MUST construct an `Authorization` header per Section 5.2: ``` - Authorization: L402 : + Authorization: L402 : ``` 4. The client MUST re-issue the original HTTP request with the `Authorization` @@ -258,27 +295,10 @@ modifications: 1. The server MUST reply with HTTP 200 OK (not 402). -2. The server MUST encode the L402 challenge as a serialized gRPC Status proto - in the `grpc-status-details-bin` trailing header. The deserialized proto - contains the macaroon and invoice: - - ```javascript - { - code: 402, - message: "missing L402", - details: { - type_url: "type.googleapis.com/google.rpc.QuotaFailure", - value: { - macaroon: "", - invoice: "" - } - } - } - ``` - -3. The server MUST include the following trailing headers: - - `Grpc-Message: missing L402` - - `Grpc-Status: 402` +2. Alongside the `WWW-Authenticate` header, the server MUST send the following + trailing headers: + - `Grpc-Message: payment required` + - `Grpc-Status: 13` (Internal) Example: @@ -287,9 +307,8 @@ modifications: Date: Mon, 04 Feb 2014 16:50:53 GMT Content-Type: application/grpc ... - Grpc-Message: missing L402 - Grpc-Status: 402 - Grpc-Status-Details-Bin: CJIDEgxtaXNzaW5nIExTQVQaeQ... + Grpc-Message: payment required + Grpc-Status: 13 ``` The L402 proxy determines whether a request is gRPC by checking whether the @@ -298,10 +317,9 @@ compatible, since gRPC clients expect an HTTP/2-speaking server. ### 7.2. Client Flow -The gRPC client flow is identical to the HTTP flow (Section 6.2). Once the -client has deserialized the proto and extracted the macaroon and invoice, it -pays the invoice and constructs the L402 credential identically to the HTTP -case (concatenating base64-encoded macaroon, colon, hex-encoded preimage). +The gRPC client flow is identical to the HTTP flow (Section 6.2). The client +MUST also transmit the final token as gRPC `Custom-Metadata`, with a key of +`"token"` and a value of the hex-encoded serialized token. Other gRPC headers and trailers are required as normal; see the [gRPC over HTTP2 specification](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md) @@ -312,14 +330,14 @@ for details. L402 credentials are intended for reuse. A client SHOULD cache and reuse its credential until the server rejects it with a new 402 challenge. An L402 can be scoped to a single backend service or apply across all services behind the -same L402 proxy, since the proxy verifies all macaroons for all backends. +same L402 proxy, since the proxy verifies all tokens for all backends. Possible revocation conditions include: -- Expiry date encoded as a caveat +- Expiry date encoded as a caveat (when using macaroons) - Exceeded usage count - Volume of usage in a time period that necessitates a tier upgrade -- Explicit server-side revocation (by deleting the root key) +- Explicit server-side revocation (by deleting the root key, when using macaroons) When a credential is revoked, the server issues a fresh 402 challenge and the client repeats the payment flow. @@ -328,9 +346,9 @@ client repeats the payment flow. ### 9.1. Transport Security -L402 credentials are bearer tokens. The macaroon and preimage are transmitted -as cleartext in HTTP headers and MUST be protected by TLS. Implementations -MUST use TLS 1.2 ([RFC 5246](https://tools.ietf.org/html/rfc5246)) or later; +L402 credentials are bearer tokens. The token and preimage are transmitted as +cleartext in HTTP headers and MUST be protected by TLS. Implementations MUST +use TLS 1.2 ([RFC 5246](https://tools.ietf.org/html/rfc5246)) or later; TLS 1.3 ([RFC 8446](https://tools.ietf.org/html/rfc8446)) is RECOMMENDED. Servers MUST NOT issue L402 challenges over unencrypted HTTP. Clients MUST NOT @@ -364,7 +382,7 @@ appropriate to their threat model. ### 9.4. Replay Protection -The macaroon itself does not inherently prevent replay. Replay protection comes +The token itself does not inherently prevent replay. Replay protection comes from the caveat and revocation mechanisms: expiry caveats, usage-count tracking, and root key deletion all limit the window in which a stolen credential is useful. @@ -387,6 +405,23 @@ compatibility with deployed clients and servers: - Clients and servers MUST accept both `LSAT` and `L402` in `Authorization` headers. +Earlier versions of this specification used `macaroon` as the key name in the +`WWW-Authenticate` challenge header (e.g., `L402 macaroon="X", invoice="Y"`) +and in the gRPC `Custom-Metadata` key. To preserve backwards compatibility with +deployed clients and servers: + +- Servers SHOULD accept `macaroon=` in addition to `token=` when parsing client + requests and `WWW-Authenticate` headers from upstream proxies. +- Clients SHOULD accept both `token=` and `macaroon=` when parsing + `WWW-Authenticate` challenge headers from servers. +- Servers SHOULD accept the gRPC `Custom-Metadata` key `"macaroon"` in addition + to `"token"`. + +The `version` parameter in the `WWW-Authenticate` header was introduced in this +revision. Older clients that do not understand the `version` parameter will +ignore it per the "unknown parameters MUST be ignored" rule. Servers SHOULD +accept requests that omit the `version` parameter. + ## 11. References - [RFC 2119: Key words for use in RFCs](https://tools.ietf.org/html/rfc2119) @@ -400,3 +435,4 @@ compatibility with deployed clients and servers: - [BOLT 11: Invoice Protocol](https://github.com/lightning/bolts/blob/master/11-payment-encoding.md) - [Macaroons: Cookies with Contextual Caveats (Google Research)](https://research.google/pubs/pub41892/) - [gRPC over HTTP2](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md) +- [bLIP-0026: L402 Protocol Specification](https://github.com/lightning/blips/blob/master/blip-0026.md)