interledger / rfcs

Specifications for Interledger and related protocols
https://interledger.org
Other
454 stars 111 forks source link

Delegated / pull payments #499

Closed emschwartz closed 5 years ago

emschwartz commented 5 years ago

Sort of a continuation of https://github.com/interledger/rfcs/issues/156

Use cases

  1. Authorizing apps/services to send from your account balance
  2. (e)Commerce and integrating with the W3C Web Payments API
  3. Subscriptions

Token options

Protocols to build the token authentication into

An interesting point that @ekrenzke raised is that with pull payments based on SPSP you can only pull money to your own account. If it's based on BTP, the authorized party can connect to your provider (connector) and send ILP payments to themselves or anyone else on the network. Enabling 3rd parties to pay 4th parties is useful for services that may need to buy additional services (hosting, for example), because they wouldn't need the money to flow through their own account first.

Another advantage of doing this in BTP is that the connector already needs to keep state and manage balance logic, so both of those would just get a little more complex, rather than us needing to implement a way to keep state in the SPSP server.

A downside of doing pull payments via BTP is that we're tying high-level application functionality to what's supposed to be a lower level and strictly bilateral protocol. (I believe this was discussed on an earlier thread but can't remember which one)

Token request flow

Thoughts, opinions, or questions?

rhuairahrighairidh commented 5 years ago

Am I thinking of the flow correctly? here’s an example walk through:

I feel like doing this at the BTP layer could end badly. It kind of breaks separation of concerns and I can't see what it brings vs just implementing desired logic in the application layer.

emschwartz commented 5 years ago

That's the correct flow.

The advantage of doing this as part of BTP instead of SPSP is that B can send money to any address on ILP instead of just pulling money to its own account. If we implement the tokens as a way to authenticate for SPSP and get a STREAM connection through which A's provider will push money to B, all the money is going to B. If B wants to send to other people, that would be a separate payment that they would initiate from their account.

sharafian commented 5 years ago

I would strongly advocate for SPSP based pull payments.

Code difficulty

Another advantage of doing this in BTP is that the connector already needs to keep state and manage balance logic, so both of those would just get a little more complex, rather than us needing to implement a way to keep state in the SPSP server.

If we wanted to re-use connector code we'd need to dynamically create a plugin for every subscription. You could alternatively keep a database with the states of all your subscriptions and then create a multi-plugin that wraps that but I'd argue that's no simpler than writing a stateful SPSP server.

Forwarding pull payments

An interesting point that @ekrenzke raised is that with pull payments based on SPSP you can only pull money to your own account. If it's based on BTP, the authorized party can connect to your provider (connector) and send ILP payments to themselves or anyone else on the network.

So long as everyone is on ILP, it should be just as easy to receive money and then just send it to another party. You can have two streams open at the same time and increase the send amount on the outgoing stream every time money comes in on the incoming stream. I wrote a similar ILP proxy here: https://github.com/sharafian/revshare-pointer

Layering concerns

I feel like doing this at the BTP layer could end badly. It kind of breaks separation of concerns and I can't see what it brings vs just implementing desired logic in the application layer.

We've already been seeing some experiments with non-BTP protocols. In the browser we use iframe communication to pass ILP packets, @adrianhopebailie and his team have been experimenting with GRPC for communication between different parts of a connector/connector-cluster, and at Coil we've considered using HTTP2 internally for all communication between services, including ILP access. If application layer logic is riding directly on BTP, then it changes that equation.

Security

Additionally, any service that wants to offer pull payments via BTP would need to give outside parties direct access to their internal ILP network. I'm sure this can be done correctly but it could open up some security holes.

Using BTP for pull payments reminds me of Lightning's idea to post directly to someone else's LND node's RPC in order to create invoices for them. It works as a solution, but it's much less elegant than something that builds on the existing network without reaching below to a lower level.

Useful SPSP Features

SPSP has another benefit, which is that it can exchange metadata before any payment occurs. We could add optional fields to the SPSP response field that can be used to view the current state of the pull payment or the schedule on which the pull payment will be refilled in the case of a subscription.

You could also leverage STREAM's features to transmit data about the payments as they're being pulled. Because the data channel of STREAM isn't used right now, it would be easy to add non-breakingly. You could use this to present an itemized report to the user about what the money was used for. Imagine you gave AWS an SPSP pull payment and every time they billed you for a service (in real time) it could be tagged with the service that the money was used for. This is achievable with BTP but it would require us to standardize a separate sub-protocol that goes alongside ILP.

Proposed name

SPSP Location Usable for Receiver-initiated Monetization (SLURM)

Web Payments

I think Web Payments would be a good way to handle the request for a SLURM, because they've already gone through the trouble of describing a data format for a retail payment. This also means you could easily use Interledger in any checkout flow. Pull payments are more desirable for a checkout flow in general, because subscriptions are such a common thing to pay for online.

emschwartz commented 5 years ago

If we wanted to re-use connector code we'd need to dynamically create a plugin for every subscription.

This is just ilp-plugin-mini-accounts with slightly different balance logic to track different tokens

If application layer logic is riding directly on BTP, then it changes that equation.

I don't think it does. I doubt we're going to get rid of BTP any time soon, even if we wanted to. Any additional protocols used will be in addition to BTP rather than instead of.

Additionally, any service that wants to offer pull payments via BTP would need to give outside parties direct access to their internal ILP network. I'm sure this can be done correctly but it could open up some security holes.

You would do this with dedicated connectors, just like you'd have dedicated infrastructure for the SPSP servers designed to push money to whoever connects. I think both of those setups are equally difficult to secure.

We could add optional fields to the SPSP response field that can be used to view the current state of the pull payment or the schedule on which the pull payment will be refilled in the case of a subscription.

That's a good point.

SPSP Location Usable for Receiver-initiated Monetization (SLURM)

:-1: sounds way too much like sludge + sperm

So long as everyone is on ILP, it should be just as easy to receive money and then just send it to another party. You can have two streams open at the same time and increase the send amount on the outgoing stream every time money comes in on the incoming stream. I wrote a similar ILP proxy here: https://github.com/sharafian/revshare-pointer

I think this is the crux of the issue. This may be technically true but it's pretty different from a business standpoint to collect money and redistribute it versus paying the end recipients directly and having only the money that's intended for you going to your account. I'll think about this some more.

sharafian commented 5 years ago

This is just ilp-plugin-mini-accounts with slightly different balance logic to track different tokens

I agree, but my point is I don't think it's any harder to upgrade an ILP mini accounts with balance logic than it is to upgrade an SPSP server with balance logic.

If application layer logic is riding directly on BTP, then it changes that equation.

I don't think it does. I doubt we're going to get rid of BTP any time soon, even if we wanted to. Any additional protocols used will be in addition to BTP rather than instead of.

Fair enough, although you may run into issues in the browser where some websocket features are missing (like setting headers). That can come up for SPSP as well, though, mostly in the context of CORS.

Additionally, any service that wants to offer pull payments via BTP would need to give outside parties direct access to their internal ILP network. I'm sure this can be done correctly but it could open up some security holes.

You would do this with dedicated connectors, just like you'd have dedicated infrastructure for the SPSP servers designed to push money to whoever connects. I think both of those setups are equally difficult to secure.

It gives the ILP infrastructure multiple concerns, though, which makes it more difficult to reason about.

Unless you're an ILSP, your ILP infrastructure sits between your internal services and an uplink into the rest of the Interledger. You might have multiple internal connectors or uplinks to handle load, and you might have some billing logic, but it purely exists to provide connectivity. All of your application logic lives in your services, which interact via Internet and Interledger with your clients.

If you add in application layer logic to your ILP infrastructure, it becomes more complicated. You have some parts of the internal network that are accessible to clients, and some areas that are accessible only by your internal services. You need to be more careful with your ILP topology because now it enforces your application logic instead of just providing connectivity.

SPSP Location Usable for Receiver-initiated Monetization (SLURM)

:-1: sounds way too much like sludge + sperm

Fair enough (it's also the name of a soft drink brand in Futurama)

I think this is the crux of the issue. This may be technically true but it's pretty different from a business standpoint to collect money and redistribute it versus paying the end recipients directly and having only the money that's intended for you going to your account. I'll think about this some more.

In both cases you're paying out to the same person, and I think that's the part most businesses would be concerned about, if they need to get tax information or do any kind of KYC.

If there were no goods/services being exchanged along the way you might also look like a money transmitter, but I think it would be more common to pay one party for a service, and then they pay some other parties whose content was used for the service.

emschwartz commented 5 years ago

I agree, but my point is I don't think it's any harder to upgrade an ILP mini accounts with balance logic than it is to upgrade an SPSP server with balance logic.

Right now, the connector and plugins are assumed to be connected to a database and passed a store. The SPSP server is currently stateless (with the exception of the ongoing stream connections held in memory).

although you may run into issues in the browser where some websocket features are missing (like setting headers)

AFAIK no special features are needed by BTP.

It gives the ILP infrastructure multiple concerns, though, which makes it more difficult to reason about.

What are the multiple concerns? Connectors manage multiple client connections and track balances and/or bandwidth for each account. Unless every customer connects via a VPN, the connectors are going to have publicly accessible endpoints. The only difference with the delegated token is that an incoming connection may either be from one of your direct customers or someone they've delegated access to. An ILSP could actually use the same token-based auth mechanism for the direct customers so you have a single flow to deal with.

Regarding the money flowing through your account: the other issue I'm thinking about is payment bandwidth. If you have a money splitter/redirection service and take 0.1% as a fee, you'd need the outgoing payment bandwidth equivalent to 100% of the money going through you rather than just enough incoming payment bandwidth to receiver your 0.1% fee. If you're keeping 90% of the money, this is obviously less of an issue.

kincaidoneil commented 5 years ago

If application layer logic is riding directly on BTP, then it changes that equation.

I don't think it does. I doubt we're going to get rid of BTP any time soon, even if we wanted to. Any additional protocols used will be in addition to BTP rather than instead of.

I'm keen on a protocol to replace BTP, but I'm unclear on how this proposal is tied to any specific transport. Whether we're using BTP, gRPC, or something else entirely, couldn't we still maintain an authentication mechanism for each that uses the same auth token/macaroon format to pull from some balance?

If we wanted to re-use connector code we'd need to dynamically create a plugin for every subscription.

This is just ilp-plugin-mini-accounts with slightly different balance logic to track different tokens

Since we're moving in the direction of dynamically instantiating accounts on the connector anyways, this doesn't seem like too big of a deal. If I'm understanding this correctly, one complexity would be the balance is shared across multiple accounts (e.g. the user authorizing the payment who accrued the balance, and the 3rd party that'd be pulling from the balance, subject to some limitation, as they'd both be separate accounts on the connector). Is that correct? Would that require a custom balance middleware?

(Just wondering on an implementation level how it would work using BTP).

sharafian commented 5 years ago

Right now, the connector and plugins are assumed to be connected to a database and passed a store. The SPSP server is currently stateless (with the exception of the ongoing stream connections held in memory).

The typical connector right now has no persistence built in; for example, moneyd has no persistence and Coil's connectors also don't make use of the connector's store functionality. The challenge of getting persistence is more related to infrastructure, while the code to connect to persistence is trivial.

It gives the ILP infrastructure multiple concerns, though, which makes it more difficult to reason about.

What are the multiple concerns? Connectors manage multiple client connections and track balances and/or bandwidth for each account. Unless every customer connects via a VPN, the connectors are going to have publicly accessible endpoints. The only difference with the delegated token is that an incoming connection may either be from one of your direct customers or someone they've delegated access to. An ILSP could actually use the same token-based auth mechanism for the direct customers so you have a single flow to deal with.

The only connectors that manage client connections are ILSPs. If you're writing an application that builds on top of Interledger, even an Interledger wallet like XRPtipbot, your users never connect to your ILP infrastructure.

If you're writing an ILP application right now, your connectors can just be dumb components that forward traffic between your application and your uplink. There's no application logic involved there; at most you have some billing logic with your ILSP.

Introducing application logic in your ILP infrastructure adds another concern by extending its logic beyond simply forwarding packets.

I'm keen on a protocol to replace BTP, but I'm unclear on how this proposal is tied to any specific transport. Whether we're using BTP, gRPC, or something else entirely, couldn't we still maintain an authentication mechanism for each that uses the same auth token/macaroon format to pull from some balance?

Any application that wants to pull money needs to speak the same bilateral protocol as the party they're pulling from. So if we wanted to let people use BTP, gRPC, etc, the sender and the receiver would need to support all of them (or have a protocol negotiation to agree on a bilateral protocol to use for that pull payment)

Since we're moving in the direction of dynamically instantiating accounts on the connector anyways, this doesn't seem like too big of a deal. If I'm understanding this correctly, one complexity would be the balance is shared across multiple accounts (e.g. the user authorizing the payment who accrued the balance, and the 3rd party that'd be pulling from the balance, subject to some limitation, as they'd both be separate accounts on the connector). Is that correct? Would that require a custom balance middleware?

Yeah, if the balance of the pull payment lives in some kind of persistence layer you'd need to tie into an external system for persistence. You also need some kind of transaction system when you have multiple readers/writers simultaneously.

kincaidoneil commented 5 years ago

After some thought, I think "caveat limited" auth tokens at the BTP layer might have other useful applications as well. (Evan may have already alluded to this)

One issue I've had with the concept of running a local moneyd instance is that there currently isn't any model for authorizing applications/websites with individual bandwidth restrictions, other than carte-blanche blocking certain origins. BTP-based pull payments + a mechanism to request a token provides a more elegant way to do this, akin to what @adrianhopebailie suggested here: https://github.com/interledgerjs/moneyd/issues/2#issuecomment-364085501.

The flow could be something like:

  1. Website/app sends a request to local server with information about their request/how much bandwidth they want.
  2. Local moneyd prompts user to authorize the request.
  3. If authorized, the server generates a bandwidth-limited auth token (e.g. by amount and/or time).
  4. App/site can connect to the local moneyd using that token and stream money as they normally would.

Would something like that be workable using the SPSP approach?

sharafian commented 5 years ago

That's a good idea; it's definitely more elegant with BTP than SPSP for that particular use case.

I would argue, though, that it's more applicable to infrastructure than it is for normal users. Maybe one of your services needs access to the twilio API (or rather a future ILP-enabled equivalent), so you allocate it some bandwidth. If the component goes haywire it can't eat up all of your money.

It's almost worth drawing a distinction between Pull Payments and Delegated Payments, because they have some differences.

Using BTP tokens to share ILP access between services/applications would be a sort of Delegated Payments, where it's based around extending ILP connectivity to another party. It's like authorizing a device to use your wifi. The application might be doing anything with that money so it makes sense to give it pretty raw access. A wallet probably wouldn't display each packet; it would be more like an API key.

For the kinds of Pull Payments you'd have between a website/a merchant and a user, you would want details like a memo, sender details, and the amount that was pulled. This works a lot better with SPSP because it allows the merchant fetch details and also transmit a memo while it pulls the money. We don't have the format yet for transmitting a memo over a STREAM connection, but if we make it then it can also be used for the push payments that already occur over SPSP. Wallets can more easily display pull payments and push payments in a cohesive manner.

If we wanted to do that on BTP, then we'd need to standardize on several side protocols in both directions for the exchange of information about the pull payment. This wouldn't have any overlap with what we're doing for push payments either.

adrianhopebailie commented 5 years ago

I think both an SPSP-initiated pull and delegation-based models are useful for different use cases.

Delegated access to the source of funds is definitely the general trend in the industry. In fact, even card payments are moving more and more to a delegated model where the issuer does a lot of checks to ensure the payer has authorized the payment.

Something to remember is that for "pull-like" payments the assumption is the payer (or their "wallet") must always be online. Hosting an SPSP server or an API that gives a third-party delegated access to your account is not something a layman user will do.

I see the delegated access model as analogous to API banking that is becoming popular (or mandatory) all over the world. While I see the value of using BTP as the protocol that a receiver would use to send payments to themselves I don't think it needs to be BTP specifically.

Any protocol that allows exchanging of ILP packets following establishment of an authenticated session would work. i.e. You authenticate a session with some connector and then begin sending it ILP packets to push money out of an account on that connector.

I'd imagine that wallets or ILSPs offering this interface would do so using a segregated part of their ILP infrastructure.

I don't see an issue with the fact that we're using BTP (or equivalent) bi-lateral protocol. The application logic exists in whatever protocol was used to request and generate the token.

emschwartz commented 5 years ago

Good points @kincaidoneil, @sharafian, @adrianhopebailie. I agree that delegated and pull payments are for different use cases, and that we probably want both. I think we can probably use the same token format, just to save on implementation complexity, though I also think the merchant/app that uses the token should treat them as opaque so it's just an implementation detail rather than a protocol concern.

Hosting an SPSP server or an API that gives a third-party delegated access to your account is not something a layman user will do.

You need this to receive money too, so pretty much every user will need one. If you're using that for receiving, you might as well also have it accessible for pull payments too.

The remaining questions are then:

sharafian commented 5 years ago

What should the protocol/format be for requesting a token? What type of access can you request (single use, fixed expiry, recurring payments, specified bandwidth, etc)?

The considerations for all of these will be different between the more 'raw' style of delegating payment permissions to an application and the more narrowly scoped situation of a merchant making pull payments from a wallet.

For the merchant pull-payment scenario, non-expiring tokens are important. It introduces a lot of friction to the user and a lot of churn to the merchant if the user needs to repeatedly re-authorize to refresh their subscription. I don't think this is a problem for the user, because your wallet could list all your active subscriptions for you to review. For these payments, you would likely want a high bandwidth limited by balance rather than a lower bandwidth spread across the month, to decrease the load on the wallet.

For the delegated case, I think a narrower bandwidth is OK and you would probably want to specify it per-second. Then the application doesn't need to worry about managing its budget; it just sends money whenever it needs to, at whatever speed it is allowed.

The single-use tokens (as in a single non-refilling amount, I assume) might be something wallets would offer their customers so they could safely do trial subscriptions, but I can't see the merchant ever requesting it.

What token format should we actually implement? My standing suggestion is a macaroon-based format where the caveats encode: a start time, a period duration in milliseconds or seconds, an amount per period, and a number of repetitions. Happy to hear other suggestions or proposals too!

If we're treating the tokens as opaque we would miss out on some of the key features of macaroons, where any party can narrow the scope of the token. That could be useful for delegated access applications but it might not be worth trading off the flexibility of not specifying one token format.

We might want to just start by just including an ID in the URL (whether BTP or SPSP) and look it up statefully on the wallet facilitating the pull payment. I think we'll need state no matter what in order to allow for revocations and balances, so we might as well also make the ID concise.

Also it seems like the discussion is moving forward past the underlying protocol we'll be using to send the payment, but I still strongly believe that SPSP is going to be a better choice for the pull-payment case between a merchant and a customer.

emschwartz commented 5 years ago

I still strongly believe that SPSP is going to be a better choice for the pull-payment case between a merchant and a customer

I don't think there's any more disagreement about that -- or at least I'm on board with that!

We might want to just start by just including an ID in the URL (whether BTP or SPSP) and look it up statefully on the wallet facilitating the pull payment. I think we'll need state no matter what in order to allow for revocations and balances, so we might as well also make the ID concise.

I'm embarrassed I didn't suggest doing that first :man_facepalming: :+1:

Agreed on balance vs bandwidth

adrianhopebailie commented 5 years ago

You need this to receive money too, so pretty much every user will need one. If you're using that for receiving, you might as well also have it accessible for pull payments too.

But the majority of users will not host this themselves. Whether it's an SPSP server or an interface for delegated access to an account on a connector we need to design for at least two different participants on the payer side in most cases.

The first is the actual payer who authorises a single payment or a subscription. The token represents this authorisation so, as with many payment systems today, it helps if that token contains proof that the actual payer authorised the payment. A digital signature of some form is the norm.

The second is the entity that has control over the payer's money. They usually host the live services that the receiver connects to; either SPSP and STREAM servers or some API for delegated access. The role of this entity is to verify the token and then manage the receiver's access to the payer's funds so that they only allow them to take what the payer intended when they authorised the payment.

This is why authorisation and payment need to be designed to be loosely coupled. The output of auth is a token, the input to payment is a token. It should be possible to mix and match different auth and payment flows (especially if we standardise the token).

adrianhopebailie commented 5 years ago

It should be possible to mix and match different auth and payment flows (especially if we standardise the token).

On this basis I propose that the design of the token is actually critical for interoperability. Using an ID and then trying to move to something else like Macaroons or JWT later will be hard.

adrianhopebailie commented 5 years ago

Some prior art to look at: https://openid.net/wg/fapi/

sharafian commented 5 years ago

The first is the actual payer who authorises a single payment or a subscription. The token represents this authorisation so, as with many payment systems today, it helps if that token contains proof that the actual payer authorised the payment. A digital signature of some form is the norm.

Does the payer hold the key or does their wallet hold the key? Introducing key management to this scheme could make things complicated for the user, but if the wallet were to hold the keys that sign the token it no longer proves anything.

Is the idea to prove to the wallet that the payer has authorized this token, or is it for the wallet to prove to 3rd parties that their client authorized the pull payment? If it's the former then the user could just make an HTTP call to their wallet to create a token.

It should be possible to mix and match different auth and payment flows (especially if we standardise the token).

In order for the full payment to go through you would need to agree on both auth and payment protocols, though. If I get a token from a wallet and it's only usable for BTP then that doesn't help me make an SPSP payment. I think @emschwartz's suggestion of an opaque token is simpler.

emschwartz commented 5 years ago

Since both BTP and SPSP (effectively) use URI-based identifiers, I was imagining it could be as simple as I give you a string in the form btp+wss://:mysecretauthtoken@connector.example or $evan.provider.example/mysecretauthtoken. The merchant / user of the token would connect to that string in the normal fashion, and it would just work. The details of how mysecretauthtoken is generated and checked are up to the user and their provider. It's nice to have standards so generic wallets would be able to support multiple providers but the merchant interaction shouldn't change based on the token format.

Using an ID and then trying to move to something else like Macaroons or JWT later will be hard.

Only if the merchant expects to be able to parse the token, which is why I don't think they should.

adrianhopebailie commented 5 years ago

Does the payer hold the key or does their wallet hold the key?

Depends what you mean by "wallet". In existing schemes the keys are held either in the chip of the payer's card or in a secure element on their mobile.

If by "wallet" you are talking about the account provider (the second stakeholder in my example) then you gain nothing by them holding the key (as you have pointed out).

Is the idea to prove to the wallet that the payer has authorized this token, or is it for the wallet to prove to 3rd parties that their client authorized the pull payment?

Both. The former is important for security but the main purpose of this separation in today's schemes is allocation of liability when things go wrong (the latter).

e.g. your bank is not liable for transactions you claim to be fraudulent if they can show you used a chip card and provided your pin (the chip will only perform the necessary crypto if you provide your pin).

But, beyond that; if the token is simply an opaque value agreed at the time of auth between the payer and their provider it is impossible to auth a payment without a communication channel between the payer and provider at the time of auth. i.e. The payer must be online.

This is the classic conundrum of pull payments. In a pull scenario the payee is the channel between the payer and their provider and you limit the use cases that you support if you assume that channel is a realtime communications channel at the time of auth.

If I get a token from a wallet and it's only usable for BTP then that doesn't help me make an SPSP payment.

Why would a token be tied to the protocol used to make the payment? What does a token look like that is only usable for BTP?

Using an ID and then trying to move to something else like Macaroons or JWT later will be hard.

Only if the merchant expects to be able to parse the token, which is why I don't think they should.

This is not about any intermediaries needing to understand the token, it is about the need to store the auth meta-data somewhere and needing to delegate the authority for that in a way that doesn't limit your use cases.

The value of a macaroon or JWT is that everything is encapsulated in the token.

Some use cases:

I agree that the opaque token that is just an identifier for the auth is simpler but it limits the possible use cases to the point that we might as well just stick with push payments AND is hard to upgrade in future.

ekrenzke commented 5 years ago

For the merchant pull-payment scenario, non-expiring tokens are important. It introduces a lot of friction to the user and a lot of churn to the merchant if the user needs to repeatedly re-authorize to refresh their subscription. I don't think this is a problem for the user, because your wallet could list all your active subscriptions for you to review. For these payments, you would likely want a high bandwidth limited by balance rather than a lower bandwidth spread across the month, to decrease the load on the wallet.

I am having trouble understanding why you would want non-expiring tokens with the possible exception of streaming services, but only for ease of use. Even then, I think it is more suitable to choose an exaggerated expiry time instead. Authorization tokens with expiry provide incentive for the merchant to "spend" the token as fast (or slow) as the payer permits. Without expiry, the payer is only able to control the upper bound of how fast the payment is streamed, and provides the recipient with one free malicious action.

If the recipient is able to control how slow the payment is streamed from the payer to the recipient without expiry, they are able to act maliciously and blame the payer for providing insufficient funds. Conversely, the wallet user could actually benefit from the merchant pulling slowly if the value of the asset they are transferring increases in value, but this should not be left up to the merchant to decide.

Sure, merchants typically want to get paid as fast as possible, but imagine a scenario where there is some charismatic chaotic-evil merchant that is just kind of bored and wants to stream the payment as slow as feasibly possible to maximize small-talk. If the payment succeeds in the arbitrary amount of time dictated by the merchant, then there isn't that much of an issue, but some funds might have been maliciously "drained" while you were busy talking about the weather or what have you. When the payer provides expiry with their token, they also set a lower bound for how slow the payment can be pulled to the recipient.

The counterargument is that, currently, there isn't a good way to verify how fast the payment was pulled anyways, without interacting with the remote server directly. The merchant could still purposefully pull slowly, but they risk having to ask the wallet user for another token, which does introduce friction. Regardless, I think that a reasonable default expiry time does exist.

I think it is important for the wallet user to have the ability to control their subscriptions and current payments before they send them, but we should enable the user (or wallet app creator with sane defaults) to set the constraints of any payments they make instead of only permitting them to react.

adrianhopebailie commented 5 years ago

Even then, I think it is more suitable to choose an exaggerated expiry time instead.

Agree. Not having a time bound on an authorised future payment is very difficult to account for as the payer. Ask any business that issues vouchers how that adds complexity to their bookkeeping, especially if the vouchers have no expiry.

sharafian commented 5 years ago

I'm thinking about expiry-less tokens in the context of a recurring payment, i.e. a voucher that "refills" every month. As a user I don't want to have an expiration date that makes me re-subscribe to some service just because they need a new auth token.

In the context of a single-use pull payment, like a retail payment, I agree that it should have some reasonable expiry. Also keep in mind that a wallet can revoke any token that it's issued for any reason even if it doesn't technically have an expiry, because the money isn't escrowed (definitely not advocating that we do escrow funds).

Not having a time bound on an authorised future payment is very difficult to account for as the payer. Ask any business that issues vouchers how that adds complexity to their bookkeeping, especially if the vouchers have no expiry.

The business is legally obligated to honor the vouchers they give out, in order to protect consumers. I don't see why you would be legally required to honor a pull payment token, because they're not being sold like gift cards or anything. If the merchant pulls with a customer's token and it doesn't work they can just cancel service or refuse to complete the purchase.

ekrenzke commented 5 years ago

Also keep in mind that a wallet can revoke any token that it's issued for any reason even if it doesn't technically have an expiry

That is true, and I think if expiry is included in the token design, this should be emphasized in the API docs. I already see this being a huge gotchya for implementers if we go forward with it.

I'm thinking about expiry-less tokens in the context of a recurring payment, i.e. a voucher that "refills" every month.

Just for clarity: are you referring to the recurring payment scenario where payments are streamed per-usage (e.g. Codius/AWS Lambda), or the subscription model (Netflix/Wolfram Alpha)? From what I have seen, the ILP community sees a lot more value in the former, but I think service providers prefer the somewhat skeuomorphic design of the latter.

edit: I just came to the realization that the pay-per-usage scenario seems kind of clunky (in this context) and not too applicable to pull payments. I'll leave all references to it anyways, but be easy on me. :)

For the more traditional subscription model, I tend to prefer a yearly expiry in case I forget about one of the many subscriptions I have. If it is the streamed-per-usage scenario, I would only need to set some upper bound on the amount and the maximum rate at which payments are streamed, but I think it also important to design a protocol which minimizes interaction between the user and the remote server.

When discussing this with @emschwartz, we came to something along the lines of:

Parameter Definition
amount The amount the payer is sending to the payee per payment period.
start The start time at which point the auth token becomes valid.
expiry The expiry time at which point the auth token becomes invalid.
intervals The number of payment periods; interval length can be calculated from (expiry-start)/intervals.

It might be useful to include a nonce that is incremented if we can successfully incorporate caveats, but I will defer that for a later post. Also, start may not be necessary, but then the length of intervals is indeterminate.

For the pay-per-usage scenario, users would be able to set the maximum amount they are willing to send and limit the bandwidth (derived from intervals and amount) accordingly. For the subscription-based scenario, users would be able to set their own terms for how much is sent per payment period and the duration in which their subscription should last. The classic "one-time purchase" scenario would remain unchanged.

I believe it is possible for an ILP-enabled wallet to provide sane defaults for most things so that the user does not have to create their auth token in a clunky interface with four (or more) different parameters. If it does enable fine adjustments of the above parameters, there are some things I would probably change about the proposed design above; such as using total_amount instead of amount.

adrianhopebailie commented 5 years ago

I don't see why you would be legally required to honor a pull payment token

What if a recurring payment is authorised because it is a repayment on a loan? Surely that means there is a legal obligation on the payer to honor the token?

As far as I know OAuth tokens always expire and there is a process for relying parties to request a new token with an extended expiry that doesn't always require the subject to authorize the new token. I assume there is a good reason for this design and my guess is it relates to revocability.

If you have very long lived tokens you also need a way to revoke them don't you?

adrianhopebailie commented 5 years ago

I would suggest that anyone working on the design of recurring payment meta-data look at some of the history of the iCal standard and other standards that have already tried to tackle modelling this data.

Let's not re-invent the wheel or relearn a lot of old lessons.

sabineschaller commented 5 years ago

I updated my pull request #501, drawing inspiration from how Paypal does subscriptions. It is quite similar to what @ekrenzke proposed but adds a few more details. I believe for wallets' display purposes it is very useful to have all of this information included in SPSP.

stale[bot] commented 5 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

If this issue is important, please feel free to bring it up on the next Interledger Community Group Call or in the Gitter chat.

emschwartz commented 5 years ago

This discussion was continued in https://forum.interledger.org/t/pull-payments/58