-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
blip-0026: L402 - Lightning HTTP 402 Protocol #26
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome! Thanks for writing this up, this is nifty. The auth protocol described here is wonderfully simple and deserves to be specified, but this document is hugely verbose and adds a wall of text and discussion that makes this protocol look downright complicated and scary. I'm confident this could be cut down by at least half without any less ability to communicate all its detail and make it much less scary to a dev who just wants to use it :)
blip-0026.md
Outdated
The following steps describe the diagram further below. It is the flow of calls | ||
that take place for a client software that wants to access a protected resource | ||
that is secured by an authentication server. | ||
|
||
As an example, we will look at the `loopd` client that wants to do a loop out | ||
swap with the Lightning Lab's loop server. | ||
|
||
**First time looping out**: | ||
|
||
1. A loop user wishes to perform a swap with the loop server. They type the | ||
command `loop out <amount>` and hit return. | ||
|
||
2. The `loopd` client program contacts the loop server to initiate the swap. | ||
|
||
3. The call from the client must always go through the authentication server | ||
reverse proxy, which in this example is `aperture`. The authentication proxy | ||
notices that the client didn't send an L402 and therefore cannot be granted | ||
access to the loop server. | ||
|
||
4. `aperture` instructs its own `lnd` instance to create an invoice over a | ||
small amount that is required to acquire a fresh credential. | ||
|
||
5. In addition to the invoice, `aperture` also creates a fresh access | ||
credential that is tied to the invoice. The credential is cryptographically | ||
constructed in a way that it is only valid once the invoice has been paid. | ||
|
||
6. The credential and the invoice are sent back to the client in the previously | ||
unused HTTP header `402 Payment Required`. | ||
|
||
7. The `loopd` understands this returned error code, extracts the invoice from | ||
it and automatically instructs its connected `lnd` instance to pay the | ||
invoice. | ||
|
||
8. Paying the invoice results in the `loopd` client now possessing the | ||
cryptographic proof of payment \(the pre-image\). This proof is stored in | ||
the client's local storage, together with the access credential. | ||
|
||
9. The combination of the access credential and the pre-image yields a fully | ||
valid L402 that can be cryptographically verified. | ||
|
||
10. The client now repeats the original request to the loop server, now | ||
attaching the L402 to the request. | ||
|
||
11. The authentication server intercepts the request, extracts the L402 and | ||
validates it. Because the L402 is valid, the request is forwarded to the | ||
actual loop server that then initiates the swap. | ||
|
||
12. The answer of the swap server is returned to the client and the swap is now | ||
initiated. | ||
|
||
13. The whole process is fully transparent to the user. The only thing they | ||
might notice is a short delay of a few seconds on the first ever loop. Each | ||
successive loop will use the same credential and will not be delayed at | ||
all. | ||
|
||
![e2e flow sequence diagram](bip-00026/e2e-flow.png) | ||
|
||
**All further loops**: | ||
|
||
1. For every new request to the server, the client now automatically attaches | ||
the credential that is stored locally. | ||
|
||
2. As long as the credential has not expired, the steps 9-13 above will be | ||
followed. If/when the credential expires, the server will start over at | ||
step 4 and instruct | ||
the client to obtain a fresh credential. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is written as an example, not a "Detailed authentication flow", it seems strange to include it in a normative "Specification" section. ISTM it would be much clearer without all the various names.
blip-0026.md
Outdated
However, there are downsides to this approach; for example, if a user switches | ||
WiFi networks, their credential becomes unusable. | ||
|
||
### HTTP Specification |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This and the gRPC section feel like "the specification" - why not replace the "Authentication Flow" section with them?
blip-0026.md
Outdated
## L402 HTTP/gRPC Protocol Specification | ||
|
||
This section defines the "L402" authentication scheme, which transmits | ||
credentials as `<macaroon(s)>:<preimage>` pairs, where the preimage is encoded |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit confused by the use of "macaroon" here - the common term for this appears to be "token", whereas macaroon has a more niche and specific definition which I'm not sure quite fits.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cryptographic properties of macaroons are desired, so the distinction is intentional.
Resources expounding on the application utility of these cryptographic properties are here: https://docs.lightning.engineering/the-lightning-network/l402/macaroons
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my note at #26 (comment) - certainly a server implementing this protocol would use macaroons or something like them, but there's no need to be specific about it here, and the thing that the server returns may be a macaroon, but from the perspective of this protocol, its just an opaque token.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and the thing that the server returns may be a macaroon, but from the perspective of this protocol, its just an opaque token.
The requirement here is that the API key itself commits to the payment hash within the invoice. This attribute is central to the protocol. Committing to the payment hash in the api key is what allows the reverse proxy implementing this protocol to be more or less stateless: given the pre-image and the macaroon (symmetric key hmac chain that includes a commitment to the payment hash in the chain), it can validate if an API key is complete or not. The API key here is a two-tuple of (macaroon, preimage)
.
This structure means that the reverse proxy doesn't need to maintain all the invoice state of the LN node it's connected to, and also doesn't need to hit an API to see if an invoice has been paid or not for each request. At high loads, such a requirement would prohibit many use cases.
It's feasible that one could use JWT's or w/e (inheriting all the baggage) other structured API keys here, but then we'd also have to specify how for each of those, the committed payment hash is to be parsed and recognized. Macaroons are more or less less standardized in their structure (tons of implementations in various languages that can all parse the same macaroons), and in use elsewhere in other independent ecosystems.
Devs are totally free to spin a similar protocol using PASETO or w/e another JWT alternatives of course. The goal of this document is to specify the L402 protocol as already defined and deployed in the wild. It's also worth noting that these headers are just for the L402 portion, the server being proxied to gets these headers and can interpret them if they wish, but can also layer w/e other authentication mechanism (oauth, etc, etc) as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The requirement here is that the API key itself commits to the payment hash within the invoice. This attribute is central to the protocol. Committing to the payment hash in the api key is what allows the reverse proxy implementing this protocol to be more or less stateless: given the pre-image and the macaroon (symmetric key hmac chain that includes a commitment to the payment hash in the chain), it can validate if an API key is complete or not. The API key here is a two-tuple of (macaroon, preimage).
Exactly, the sensible way to implement this is the stateless approach, but it also doesn't need to be any specific format, and I'm also not convinced the spec has to write out a specific format - certainly a server could implement this in a stateful way (or commit to some other id which is used to derive the payment hash, index into a later-generated map/DB of payments, etc), it would just be less performant.
It's feasible that one could use JWT's or w/e (inheriting all the baggage) other structured API keys here, but then we'd also have to specify how for each of those, the committed payment hash is to be parsed and recognized.
Right that was my point below, I'm not convinced it makes sense to do that specification here - it seems orthogonal to the actual specification of an authentication flow, and removing it entirely doesn't take away from the ability of someone to read this document and fully implement it in an interoperable way.
If would also make sense as an appendix, but focusing on it throughout the document only makes the document more confusing as there's more crammed in what is otherwise a nicely simple authentication scheme.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Kinda feel like there's a disagreement here in terms of what's in scope of the L402 nomenclature.
I'd classify it as the "data pieces and their format in the HTTP headers (or grpc calls)". Feels like there's a strong opinion herein to also include the authentication token format and specification, but it's pretty obvious to me that these are separable/unimportant from a client's perspective.
For any client that wants to know how to parse and pay/return a call from an L402 response, the auth token format is a distraction. In that case, the "data pieces and format" are all that really matter.
If there's other data or formatting that we should consider, that's probably worth documenting here. But the server side security/auth and/or how stateful/stateless it needs to be seems like an implementation detail.
This structure means that the reverse proxy doesn't need to maintain all the invoice state of the LN node it's connected to, and also doesn't need to hit an API to see if an invoice has been paid or not for each request.
This is a nice property that you can implement in any way/with a variety of tokens, but I'd argue that it's a "nice to have" of what you can do with the L402 tokens+preimages. You can also dumbly store state and do lookups (which you kinda have to do anyway for time-based access tokens / and or there different approaches to this).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but it's pretty obvious to me that these are separable/unimportant from a client's perspective.
Agreed, note that this information is only really relevant to the L402 proxy. The web service may still require the client to attach normal authentication information such as cookies or w/e other custom information. In most cases, the L402 proxy can be oblivious about the actual request information it's proxying, it only needs to ensure all the headers are copied over as normal. A client also doesn't have to introspect into the credential at all, it just encodes it with base64, then puts it where the server expects it.
The expectation isn't that all active web services switch over to macaroons, it's that only the proxy needs to care about it, and otherwise the API backend can go unchanged.
I've updated these sections to mention the optimization (committing to the hash in the credential), and weakened the language around verification.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
proxy // in-app HTTP handler middleware is baaaaaasically the same thing only difference is which machine it's running on, no?
I don't understand how where the L402 is being handled has a material impact on the specification of the "data pieces and their format" which is kiinda all we need from a spec?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, I can see why there might be an argument to keeping the specification here agnostic on the encoding of the token itself, but as someone who has implemented this as a middleware already, I do think there are benefits to having this specified as well. By standardizing the full encoding you make the L402 token itself much more portable such that clients that don't have to have a relationship with the server itself in order to know how to decode and validate the macaroon. If the encoding is standardized, then any consumer of the L402 will know how to deserialize the macaroon portion, read the payment hash and validate against the preimage.
There's also ecosystem benefits to having a system like this be cross-compatible. As an example, using the LSAT Playground (I guess I need to rebrand this now...) you can validate an L402 generated from boltwall or aperture, you can even take an L402 generated from aperture, add a caveat in the playgrond, and then have it validate against a server running boltwall middleware. You get additional benefits imo when you want to start running in environments like Nostr (if we could get L402 auth standardized for nostr) where you might have different clients and servers needing to interoperate, or something like https://sphinx.chat.
This is particularly useful when caveats come in to play so that clients can introspect their token to see how much time might be left before their authorization expires for example. So all of this plays a pretty important role in the nature of these being stateless: even though it could be encoded in other ways, having it be standardized makes it far more portable.
I don't understand how where the L402 is being handled has a material impact on the specification of the "data pieces and their format" which is kiinda all we need from a spec?
Aren't the "data pieces and their format" covered by specifying the token being a base64 encoded macaroon?
hey yall, i've been making a L402 lib for the CLN ecosystem. Here's a bit of feedback.
Cool protocol, really nice that this finally is getting some proper documentation that we can do cross implementation on |
In this commit, we add a bLIP for the L402 (formerly known as LSAT) protocol. The L402 protocol presents a standardized way of adding LN micropayments to any existing HTTP-REST or gRPC API. The L402 protocol repurposes the HTTP 402 Payment Required error code with the necessary authentication headers required to bind a request's validity to the payment of an LN invoice. Macaroons are used as flexible authentication credentials (supports custom caveats, attenuation, etc) which allow an L402 reverse-proxy to validate an L402 API key without backend LN node interaction for each request (the macaroon commits to the payment hash).
Thanks for the feedback @niftynei!
The latest push significantly cuts down on the size of the document. Further edits are likely possible as well near the start and end of the specification.
The latest iteration weakens the language around macaroons, and moves the section on a suggested structure to the appendix. You're correct that anything can be used in practice, IMO given the macaroons are already specified and standardized, I think it makes sense to nudge proxy implementations in that direction. Note that clients don't need to introspect into them at all, and just serialize them where expected. It also isn't expected the API backends rely soley on L402 for in-depth authentication, normal auth headers or cookies or w/e can still be used. The proxies are meant to be loosely coupled to the backends they support, such that any API can be put in front of a proxy and Things Just Work^TM. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added suggested comments to update (at least the HTTP section) to conform to the nomenclautre i'm using in chargesats
(macroon -> token).
Moving the Specification up within the first 200 lines is a massive improvement from befrore. 👌
|
||
2. The server decides that payment is required to access the endpoint. They | ||
return a HTTP status code of `402` along with a `WWW-Authenticate` header | ||
containing a macaroon and invoice. The macaroon commits to the payment hash |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
containing a macaroon and invoice. The macaroon commits to the payment hash | |
containing a token and invoice. Ideally, the token commits to the payment hash |
payment pre-image `r` to the payment hash `H`, `H = sha256(r)` | ||
|
||
4. The client re-issues the request with a `Authorization` header that includes | ||
the payment preimage `r`, and the macaroon sent by the server. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the payment preimage `r`, and the macaroon sent by the server. | |
the payment preimage `r`, and the token sent by the server. |
the payment preimage `r`, and the macaroon sent by the server. | ||
|
||
5. The server verifies the cryptographically verifies the authenticity and | ||
integrity of the macaroon, then ensures the payment hash committed to in the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
integrity of the macaroon, then ensures the payment hash committed to in the | |
integrity of the token, then ensures the payment hash committed to in the |
|
||
5. The server verifies the cryptographically verifies the authenticity and | ||
integrity of the macaroon, then ensures the payment hash committed to in the | ||
macaroon `H`, satisfies the relation the `H = sha256(r)`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
macaroon `H`, satisfies the relation the `H = sha256(r)`. | |
token `H`, satisfies the relation the `H = sha256(r)`. |
|
||
6. The server returns a 200 OK error code along with the specified resource. | ||
|
||
If the service supports persistent L402 credential re-use, then a client SHOULD |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the service supports persistent L402 credential re-use, then a client SHOULD | |
If the service supports persistent L402 token re-use, then a client SHOULD |
?? not sure about this one. Do you mean something other than the auth/hmac token here?
In other words, to receive authorization, the client: | ||
|
||
* Pays the invoice from the server, thus revealing the invoice’s preimage | ||
* Constructs the L402 by concatenating the base64-encoded macaroon\(s\), a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* Constructs the L402 by concatenating the base64-encoded macaroon\(s\), a | |
* Constructs the L402 by concatenating the encoded auth token\(s\), a |
* Constructs the L402 by concatenating the base64-encoded macaroon\(s\), a | ||
single colon \(":"\), and the hex-encoded preimage. | ||
|
||
Since the macaroon and the preimage are both binary data encoded in an ASCII |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the macaroon and the preimage are both binary data encoded in an ASCII | |
Since the auth token and the preimage are both binary data encoded in an ASCII |
based format, there should be no problem with either containing control | ||
characters or colons \(see "CTL" in [_Appendix B.1 of | ||
\[RFC5234\]_](https://tools.ietf.org/html/rfc5234#appendix-B.1)\). If a user | ||
provides a macaroon or preimage containing any of these characters, this is to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
provides a macaroon or preimage containing any of these characters, this is to | |
provides an auth token or preimage containing any of these characters, this is to |
be considered an invalid L402 and SHOULD result in a 402 and authentication | ||
information as specified above. | ||
|
||
If a client wishes to send the macaroon `"AGIAJEemVQUTEyNCR0exk7ek90Cg=="` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If a client wishes to send the macaroon `"AGIAJEemVQUTEyNCR0exk7ek90Cg=="` | |
If a client wishes to send the auth token `"AGIAJEemVQUTEyNCR0exk7ek90Cg=="` |
must be skipped by the authorizer as the macaroon holder can further attenuate | ||
the macaroon for other applications. | ||
|
||
### Macaroon Revocation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
### Macaroon Revocation | |
### Auth Token Revocation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Woot! Exciting to see this being formalized and to hear other people are working on it 🎉
up the ladder. Typically, a user must _manually_ navigate a web-page to request | ||
an upgrade to a higher tier, or downgrade to a lower tier. With the L402 | ||
standard, tier upgrades can easily be automated: the user hits a new endpoint | ||
to obtain an _upgraded_ L402 which _encodes_ additional functionality or |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just noting this part here wrt to the conversations about if macaroons are implementation detail or part of the spec. Using macaroons for the token is part of what makes this possible since attenuation like this is part of the design goal of macaroons.
lacks credentials or contains an L402 that is invalid or insufficient in some | ||
way: | ||
|
||
1. Ths server SHOULD derive a economical price for the endpoint expressed in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1. Ths server SHOULD derive a economical price for the endpoint expressed in | |
1. Ths server SHOULD derive an economical price for the endpoint expressed in |
The `L402` protocol was formerly known as `LSAT`. In order to preserve | ||
backwards compatibility with clients, anywhere `L402` is used within HTTP | ||
headers or requests, a valid protocol flow with the string `LSAT` should also | ||
be accepted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉
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/). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be good to reference some implementations as well. Not all of them are interoperable unfortunately, so highlighting ones that are standard compliant would be useful as well as for further reference on how they work which can be helpful to understanding.
|
||
To prevent abusers of a macaroon-based authenticated service, a macaroon should | ||
be able to be revoked. This can be achieved by having the minter remove the | ||
macaroon’s corresponding root key. By doing so, the minter will never be able |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately this makes the system somewhat less stateless :-/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's purely optional, otherwise you can implement time based revocation just via a caveat expiry. I think it also depends on the service, some may be able to get away with a single global service key, while others may already require per user/account keys for the macaroons. In theory, you can have the best of both worlds if a deterministic scheme is used to derivation of the symmetric keys.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for making this more readable. I think still a good chunk of text could be cut down.
# Motivation | ||
|
||
The early creators of the Web created a cut out for a future Internet-native | ||
payment system in the form of the HTTP 402 Payment Required status code. This | ||
status code was intended to be returned if payment was required in order to be | ||
able to fetch/interact with the resources at a given HTTP endpoint. The 402 | ||
status code thus presented a way to enable HTTP-native payment metered APIs on | ||
the Web. The rise of the Transport Layer Security protocol, enables payments on | ||
the Web, albeit via client-side interfaces that rely on opaque payment networks | ||
such as credit cards. With the rise of Bitcoin, and the Lightning Network, the | ||
Internet now has a native digital currency and a low-cost, low-latency, high | ||
volume payment system to enable highly scalable payments over open payment | ||
infrastructure. | ||
|
||
This document specifies the L402 protocol which utilizes the 402 status code, | ||
macaroons, the Lightning Network, and special authorization headers to create a | ||
native payment-metering system for the Web. An L402 credential can serve both | ||
as authentication, as well as a payment mechanism \(one can view it as a | ||
ticket\) for paid APIs. By leveraging L402, a service or business is able to | ||
offer a new tier of paid APIs that sit between free, and subscription: pay as | ||
you go. | ||
|
||
One can view L402 credential (a macaroon) as a fancy authentication credential | ||
or cookie. They differ from regular cookies in that they're a cryptographically | ||
verifiable bearer credential. An L402 credential _encodes_ all its capabilities | ||
within a macaroon which can only be created by the end service provider. The | ||
L402 specification uses a combination of `HTTP` as well as 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This and the abstract repeat almost entirely the same things, one or the other should be removed.
|
||
# Abstract | ||
|
||
L402 is a protocol standard based on the HTTP 402 Payment Required error code |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is now a bit confusing - the abstract and motivation sections repeatedly refer to the auth token as a token or macaroon interchangeably. I'd suggest sticking with token as its the more general/accepted term, but either way just stick with one.
|
||
This section defines the client-side L402 authentication headers, which | ||
transmits credentials as `<macaroon(s)>:<preimage>` pairs, where the preimage | ||
is encoded as hex and the macaroon is encoded as base64. Multiple macaroons are |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this mean the client has to re-encode what it got as base64, or that we're requiring the server to encode the auth tokens as base64? If its the server, it should be in the preceding section, not in the section about the client behavior.
|
||
## L402 HTTP/gRPC Protocol Specification | ||
|
||
### Server HTTP Authentication Headers |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given the auth flow sections below repeat this info, can we just elide the two "authentication headers" sections entirely?
|
||
A valid response header MUST take the form of: | ||
``` | ||
WWW-Authenticate: L402 macaroon="M", invoice="P" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this define the invoice as bolt11 (not necessarily the parameter name, but just written out in the requirements, rather than simply "lightning invoice", which is now ambiguous).
the L402 authentication scheme and the macaroon needed for the client to | ||
form a complete L402. | ||
|
||
A valid response header MUST take the form of: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For forwards-compat, should we specify that unknown key=V parameters are ignored? eg that would allow use of bolt12 offers or some other invoicing scheme in the future.
Any updates on this since last year? /cc @Roasbeef |
What updates are you looking for specifically? |
Presumably either feedback being address or the author saying they don't want to address feedback so we can merge this! :) |
@slavakurilyak Hi, I've been gathering some significant feedback from a dozen or so teams/companies actively working on integrating the protocol into their offerings. We've been meeting once a month or so to discuss improvements to the protocol and also generally how things are fairing in the wild. I plan to make future PRs to start to incorporate some of this feedback (eg: ways to handle more stateful APIs, structured information outside the macaroon caveats, etc, etc). With all that said, I'll move to merge this in a few days (addressing the obvious typos/wording improvements suggested above), as the current text has been adequate for those seeking to actively build upon the protocol, and some felt that the lack of a merged PR meant the protocol was in an ambiguous state. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the push @Roasbeef, I'm thrilled about this! 🚀
Regarding L402, I would suggest focusing on macaroons and having the spec define how caveats are structured (as we do here). Later, we can even include n appendix on "standard" caveats (e.g., expires vs expires_at). But I would do that once we observe their usage in the wild.
I'd like to propose two additions:
Versioning in the WWW-Authenticate
header: Adding a version field apart from "macaroon" and "invoice" would allow for different "encoding" in the future, enabling clients/servers to understand and respond appropriately. If we call the current version V0
L402 version="V0" macaroon="X", invoice="Y"
Returning multiple macaroons/invoices: While the exact implementation in the WWW-Authenticate header is uncertain, it would be beneficial to return an array of "Offers" with specific macaroons/invoices for each one, along with data explaining their purpose (like "supported plans" and what each plan includes). If versioning is part of the protocol (🤞 ), we can fix this in the future and even return them in the response body instead of the header in future versions of the protocol.
|
||
1. The server MUST verify the cryptographic authenticity and integrity of the | ||
credential. | ||
1.1. If a credential is invalid, then the server MUST return a 401 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The markdown needs to be fixed. The subsections are not rendered properly. (1.1, 3.1 and 3.2)
|
||
1. Should verify that the contained BOLT 11 invoice doesn't request an | ||
excessive amount of Bitcoin. | ||
1.1. If so, then the client SHOULD abandon the HTTP request. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
format: same here
are essential to the verification of macaroons, so they must be stored securely | ||
and reliably. | ||
|
||
#### Macaroon Identifier |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we may be over specifying a bit here.
Why wouldn't user_id
/macaroon_version
be caveats?
An L402 credentials are linked to a specific challenge (invoice) and what identifies that invoice is the payment_hash
so I would go with that in my implementation and leave everything else to caveats.
Not sure why this needs to be specified though? Unlike biscuits, macaroons can only be validated by the issuer, so the id should be whatever the issuer wants without encoding extra information/encoding whatever the issuer wants.
|
||
For the L402 protocol the challenge takes the following form: | ||
``` | ||
L402 macaroon="X", invoice="Y" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you are referring to two different things here @positiveblue . From what I see Aperture does add the "
double-quotes when generating the "challenge" header, as can be seen here. Sulu replicates this functionality, as does lsat-js.
It is the challenge response with the L402 token that does not use "
, as can be seen in the code from Aperture. Sulu does the same.
I think the use of "
in the www-authenticate header, while to my knowledge not strictly necessary, its actually quite typical. See for example:
See also here.
In my opinion we should keep with standard practices here, so I see no problem maintaining the "
for the www-authenticate header.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right, I was following this diagram and checked the wrong header:
sequenceDiagram
participant L as Lightning Node
participant C as Client
participant S as Server
C->>S: GET HTTP/1.1 Request
S->>C: HTTP/1.1 402 Payment Required
Note over S: WWW-Authenticate: L402 macaroon=X invoice=Y
C->>L: Pay invoice
L->>C: Returns pre-image
C->>S: GET HTTP/1.1 Request
Note over C: Authorization: L402 macaroon:preimage
S->>S: Verify L402 authorization
S->>C: HTTP/1.1 200 OK
I see that even aperture does it that way too
Case closed
participant S as Server | ||
C->>S: GET HTTP/1.1 Request | ||
S->>C: HTTP/1.1 402 Payment Required | ||
Note over S: WWW-Authenticate: L402 macaroon=X invoice=Y |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note over S: WWW-Authenticate: L402 macaroon=X invoice=Y | |
Note over S: WWW-Authenticate: L402 macaroon="X" invoice="Y" |
In this commit, we add a bLIP for the L402 (formerly known as LSAT)
protocol. The L402 protocol presents a standardized way of adding LN
micropayments to any existing HTTP-REST or gRPC API. The L402 protocol
repurposes the HTTP 402 Payment Required error code with the necessary
authentication headers required to bind a request's validity to the
payment of an LN invoice. Macaroons are used as flexible authentication
credentials (supports custom caveats, attenuation, etc) which allow an
L402 reverse-proxy to validate an L402 API key without backend LN node
interaction for each request (the macaroon commits to the payment hash).