Skip to content

Commit

Permalink
Added registerProvider() and getProviders() API calls.
Browse files Browse the repository at this point in the history
  • Loading branch information
msporny committed Jul 1, 2013
1 parent bef504f commit a0885d7
Showing 1 changed file with 106 additions and 22 deletions.
128 changes: 106 additions & 22 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ <h1>Introduction</h1>
<p>
This API enables Web content to initiate payment or issue a refund for a
product or service. Once implemented in the browser, an author may issue
<code>navigator.payment()</code> function to initiate a payment.
<code>navigator.transact.pay()</code> function to initiate a payment.
</p>
<section class="informative">
<h2>How to Read this Document</h2>
Expand All @@ -153,7 +153,7 @@ <h1>WebPayments Architecture</h1>
<p>
An open web app will interact with a
<a href="https://wiki.mozilla.org/WebAPI/WebPaymentProvider">Payment Provider</a>
via <code>navigator.payment()</code> and receive notifications POSTed to its
via <code>navigator.transact.pay()</code> and receive notifications POSTed to its
server about the result of each payment. Users will see a payment flow hosted
by the Payment Provider in a special window on the device.
</p>
Expand All @@ -163,7 +163,7 @@ <h2>Payment Flow Overview</h2>
<ul>
<li>
The app initiates a payment by signing a JSON Web Token [[!JWT]] request
and calling <code>navigator.payment()</code>.
and calling <code>navigator.transact.pay()</code>.
</li>
<li>
This starts the buyflow in a content iframe inside a trusted dialog
Expand Down Expand Up @@ -207,7 +207,7 @@ <h3>Definitions</h3>
<dt><tdef>Application</tdef></dt>
<dd>
Open Web App which offers digital goods to be sold. OWAs charge users
via <code>navigator.payment()</code> and require a client and server.
via <code>navigator.transact.pay()</code> and require a client and server.
</dd>
<dt><tdef>Application Key</tdef></dt>
<dd>
Expand All @@ -228,13 +228,13 @@ <h3>Definitions</h3>
<dd>
Developer portal and application repository. Developers can submit apps to
the Marketplace so users can purchase and download the apps. The Marketplace
uses the <code>navigator.payment()</code> function to charge users for
uses the <code>navigator.transact.pay()</code> function to charge users for
application purchases.
</dd>
<dt><tdef>Payment Provider</tdef></dt>
<dd>
A client/server web application that serves content in a special iframe
controlled by <code>navigator.payment()</code>. This conforms to
controlled by <code>navigator.transact.pay()</code>. This conforms to
the
<a href="https://wiki.mozilla.org/WebAPI/WebPaymentProvider">Payment Provider</a>
spec. The provider accepts payment from a user and disperses income to the Developer.
Expand All @@ -255,7 +255,7 @@ <h3>Definitions</h3>
<h3>Sign-in</h3>
<p>
This is an implementation detail of the <tref>Payment Provider</tref>.
The <code>navigator.payment()</code> API does not prescribe any user
The <code>navigator.transact.pay()</code> API does not prescribe any user
authorization scheme.
</p>
<p class="issue">
Expand All @@ -267,7 +267,7 @@ <h3>Sign-in</h3>
<h3>Developer Registration</h3>
<p>
This is an implementation detail of the <tref>Payment Provider</tref>.
The <code>navigator.payment()</code> API facilities two parties in making a
The <code>navigator.transact.pay()</code> API facilities two parties in making a
transaction: 1) a Developer and 2) a Payment Provider. It does not
facilitate any part of the registration process.
</p>
Expand Down Expand Up @@ -305,7 +305,7 @@ <h3>Initiating a Payment</h3>
</li>
<li>
The <tref>Application</tref> bubbles up the JWT to the client and calls
<code>navigator.payment([theJWT])</code>. This begins the hosted buy flow
<code>navigator.transact.pay([theJWT])</code>. This begins the hosted buy flow
within a special window on the <tref>User Agent</tref>.
</li>
</ol>
Expand Down Expand Up @@ -403,16 +403,16 @@ <h3>Initiating a Payment</h3>

<p>
For a user to make a purchase, the Application must execute the Javascript
method <code>navigator.payment()</code> with one or more signed payment
method <code>navigator.transact.pay()</code> with one or more signed payment
requests (the JWTs). For example, the app might have a 'buy' button that
triggers this method when clicked. Then <code>navigator.payment()</code> method
triggers this method when clicked. Then <code>navigator.transact.pay()</code> method
should take the signed payment JWT or an array of them. It will return a
<a href="https://developer.mozilla.org/en/DOM/DOMRequest">DOMRequest</a> object
that the developer can use to monitor the progress of the operation.
</p>

<pre class="example" title="Initiating a payment via the navigator.payment() method">
var request = navigator.payment([signedJWT1, signedJWTn]);
<pre class="example" title="Initiating a payment via the navigator.transact.pay() method">
var request = navigator.transact.pay([signedJWT1, signedJWTn]);

request.onsuccess = function () {
// The payment buy flow completed without errors.
Expand All @@ -421,13 +421,13 @@ <h3>Initiating a Payment</h3>
}

request.onerror = function (errorMsg) {
console.log('navigator.payment() error: ' + this.error.name + ': ' + errorMsg);
console.log('navigator.transact.pay() error: ' + this.error.name + ': ' + errorMsg);
}
</pre>

<ol>
<li>
The <code>navigator.payment</code> method will open a payment request
The <code>navigator.transact.pay</code> method will open a payment request
confirmation screen based on the received JWTs, so the user can confirm and
choose the payment method that is more appropriate for him.
The User Agent would only
Expand Down Expand Up @@ -596,7 +596,7 @@ <h4>Chargeback</h4>
<section>
<h4>Refunds</h4>
<p>
Refunds are not yet supported by the <code>navigator.payment()</code> API.
Refunds are not yet supported by the <code>navigator.transact.pay()</code> API.
<strong>At a future date, an Application may be able to request a refund
like this</strong>:
</p>
Expand Down Expand Up @@ -628,7 +628,7 @@ <h1>Payment Provider facing API</h1>
Figure out how to reference the
<a href="/WebAPI/WebPaymentProvider" title="WebAPI/WebPaymentProvider">WebPaymentProvider</a>
spec for details on how to implement a payment provider for
<code>navigator.payment()</code>. It may be that we need to fold that into this
<code>navigator.transact.pay()</code>. It may be that we need to fold that into this
spec.
</p>
</section>
Expand All @@ -641,13 +641,14 @@ <h2>The Application Programming Interface</h2>
MUST implement the entirety of the following API.</p>

<section>
<h3>NavigatorPayment</h3>
<h3>NavigatorTransactions</h3>

<p>Navigator Payment is the high-level programming interface that Web
developers use to initiate payments.</p>
<p>Navigator Transactions is the name of the high-level programming
interface that Web developers use to initiate payments. If MUST be
made available via the <code>navigator.transact</code> object.</p>

<dl title="interface NavigatorPayment" class="idl">
<dt>DOMRequest payment()</dt>
<dl title="interface NavigatorTransactions" class="idl">
<dt>DOMRequest pay()</dt>
<dd>
Initiates a payment or refund given an array of JSON Web Tokens [[!JWT]]
describing the types of actions to perform.
Expand All @@ -658,6 +659,89 @@ <h3>NavigatorPayment</h3>
of payment operations to perform.</dd>
</dl>
</dd>
<dt>DOMRequest registerProvider()</dt>

This comment has been minimized.

Copy link
@kumar303

kumar303 Jul 1, 2013

Member

The more I think about this method the more I think we don't need it for the case of merchants who want to support non-whitelisted providers. This case is step one in removing the whitelist. If a merchant wants to pay with a non-whitelisted provider the payment flow could simply prompt for registration before beginning the transaction. At the end of the transaction, the provider would be saved to device preferences. Instead of adding a registerProvider method we could perhaps support this case by modifying the payment JWT format to include providerRegistrationURL or something.

This comment has been minimized.

Copy link
@kumar303

kumar303 Jul 1, 2013

Member

on second thought, a providerRegistrationURL doesn't make sense in the payment JWT. We expose window.mozPaymentProvider to the provider's web context. We could add a flag like window.mozPaymentProvider.isRegistered and window.mozPaymentProvider.register() so that the provider can present its own UI to complete registration as part of a streamlined pay flow. Before the non-whitelisted payment provider's URL is loaded, the chrome UI could warn "You are about to pay with an unknown provider Name at URL, do you wish to proceed? Press the X to cancel at any time" (or something like that). This should mitigate phishing while also putting UX controls in the hands of the provider.

This comment has been minimized.

Copy link
@msporny

msporny Jul 1, 2013

Author Member

How would the merchant prompt for registration where the customer is not very technologically savvy? That is, if there are 100 different PaySwarm payment providers out there, and a merchant accepts PaySwarm-based payments, how does the registration flow look for the customer? Do they have to pick from 100 different icons? Type out a URL to their payment provider? Type out an e-mail address that their payment provider gave them?

I think registration is easier when you only have a handful of payment providers in the market. For example, if all the customer has to pick from is PayPal, Amazon, and Google Wallet, the registration screen is simple. It's much more difficult when you have a potential for hundreds of different payment providers.

This comment has been minimized.

Copy link
@dlongley

dlongley Jul 1, 2013

Member

I think we should have registerProvider available regardless of the purchase flow -- as payment providers may want to call it on their own site. A customer may be registering with a payment provider outside of a purchase flow.

This comment has been minimized.

Copy link
@kumar303

kumar303 Jul 2, 2013

Member

@msporny good question. But in the case of a merchant supporting pay swarm, isn't this a moot point? Wouldn't the prompt simply be something like "this merchant is asking to pay via the PaySwarm protocol, proceed?" For other cases, we may have to limit the number of providers that a merchant can support.

@dlongley good point. Like popups I think registerProvider would need to be initiated by a user action only such as clicking a "register" button. The current navigator.mozPay() works the same way. I thought of that because registerProvider seems like it can get spammy really fast.

This comment has been minimized.

Copy link
@msporny

msporny Jul 10, 2013

Author Member

For the PaySwarm use case, with the current implementation, the site still needs to be able to get which PaySwarm provider the purchase request should be sent to. In the future, we could have the browser do this re-direction to the proper payment provider, but creating a polyfill for that would be difficult to do (maybe). There is also the case where the vendor website doesn't trust the PaySwarm payment provider that the customer has picked (due to increased fraud over the last 24 hours, or some other metric). We haven't put a great deal of thought into a polyfill for PaySwarm purchasing that would be able to pick which PaySwarm provider to use and re-direct to that payment provider without having something centralized. Even if we do that, it's not clear how we'd give the vendor the choice of rejecting the start of the buyflow. Not saying it can't be done, just saying that we don't have a working solution for it yet.

I agree about the user-initiated registerProvider call, we don't want it to get too spammy.

This comment has been minimized.

Copy link
@dlongley

dlongley Jul 10, 2013

Member

Actually, I think we may be able to design around (and mostly have) needing the vendor site to know the buyer's PaySwarm Authority with the first purchase (subsequent purchases that may occur via a background API could depend on the information received in the initial receipt). For the fraud case we can discuss ways to better prevent it from happening before the customer is charged -- but the vendor would not accept a receipt from a rogue PaySwarm Authority.

<dd>
<p>
Registers a payment provider with the browser such that future
transactions may provide an interface to the user to select
which payment provider that they would like to use to complete a
transaction.
</p>
<p>
Registering a payment provider can alter the choices given to the User when a
transaction is processed. In the worst case, an attacker could register a fake
payment provider that collects all of the User's credit card or banking details.
In order to ensure that the User is protected from this sort of attack, the
User Agent MUST provide a special interface that is not easily spoofed by
an attacker.
</p>

<p class="issue">
We may want to place a number of restrictions on sites
doing the registration, such as: 1) The call must be done on a page served over
TLS and with no scripts loaded from a non-secure channel. 2) The domain for the
<code>id</code> and <code>services</code> URLs must match the domain
for the page requesting the registration, etc.
</p>

<dl class="parameters">
<dt>object provider</dt>
<dd>An object consisting of the following keys and values:

This comment has been minimized.

Copy link
@kumar303

kumar303 Jul 1, 2013

Member

on Firefox OS, payment providers are registered with these parameters: https://github.com/mozilla-b2g/gaia/blob/master/build/payment-prefs.js Only the uri and type are used in practice. It's important to note that the uri in this case is to that of the payment flow.

<dl style="margin-left: 1em;">
<dt><code>id</code> (optional)<dt>
<dd>A URL identifier for the provider.</dd>

This comment has been minimized.

Copy link
@kumar303

kumar303 Jul 1, 2013

Member

Perhaps this should be the URL to the beginning of the payment flow?

This comment has been minimized.

Copy link
@msporny

msporny Jul 1, 2013

Author Member

In PaySwarm we differentiate between the identity of the provider, and the service URLs that the provider exposes. I think the beginning of the payment flow is a service URL, what do you think?

This comment has been minimized.

Copy link
@kumar303

kumar303 Jul 2, 2013

Member

I'm not sure what a service URL is. By beginning of the payment flow I meant the URL that a customer would load to begin a transaction (e.g. a PIN prompt). Maybe we need an identity URL in addition to a start-transaction URL? mozPay() as is needs to know the start-transaction URL.

This comment has been minimized.

Copy link
@msporny

msporny Jul 10, 2013

Author Member

In PaySwarm, we're defining a "service URL" as any standardized web service that is provided by the payment provider. So, initiating a transaction would have a service URL that you POST some data to. Initiating a payment would have a service URL. The start of the payment flow would have a service URL. So, I think I know what you mean and it does fit into the model we have. We can discuss more about this on the call. There are pros/cons to each approach.

<dt><code>type</code><dt>
<dd>
<p>
The type of payments supported by the payment provider. Valid values include:
<code>MozPay</code>, <code>CreditCard</code>, <code>ACH</code>,
<code>PayPal</code>, <code>AmazonPayments</code>,
<code>GoogleWallet</code>, <code>PaySwarm</code>.

This comment has been minimized.

Copy link
@kumar303

kumar303 Jul 1, 2013

Member

as you mentioned, this probably makes sense as a freeform string for now. In the current mozPay we assume that type strings are unique; they are used to route JWTs to payment providers.

This comment has been minimized.

Copy link
@msporny

msporny Jul 1, 2013

Author Member

+1 - sounds good. The payment specifications that build on top of this spec can outline what the string should be in each case.

</p>
<p class="issue">
Most of these types don't make sense as they're not
interoperable with any other system and don't have a protocol for notifying
sites that a payment has been made successfully. We may just want to make
this a free-form string and let payment providers and merchants settle on
interoperable values.
</p>
</dd>
<dt><code>services</code> (optional)<dt>
<dd>
A URL that can be used to determine more information about the payment provider
Web service endpoints by the User Agent or Merchant.
</dd>
</dl>
</dd>
</dl>
</dd>
<dt>DOMRequest getProviders()</dt>
<dd>
<p>
Retrieves all of the payment providers that are registered with the User Agent
that match the query criteria given and were authorized to be included in
the response by the User.
</p>
<p>
It is not always preferable for a User to have all of their payment providers
exposed to a Merchant. In the worst case, an attacker can use this information
to execute spear-fishing attacks against the User. The User Agent should
provide the User with an interface that allows them to select which providers
they want to expose to the merchant. In many cases, the User will only want to
expose one, which will make the purchase process proceed more fluidly.
</p>
<p>
The result will be an array of payment providers that are in the same format
as the objects passed to the <code>registerProvider()</code> method.

This comment has been minimized.

Copy link
@kumar303

kumar303 Jul 1, 2013

Member

I think this method is too risky to expose to merchants. It's too much of a privacy leak to grant access to a user's registered payment providers and I don't think we should allow it even if consensual. I don't have a good alternative though. It might be easier to focus in on the problem more. What do we want merchants to do with this info? We want to give them a chance to display a one-click buy button, right? Or something else?

This comment has been minimized.

Copy link
@msporny

msporny Jul 1, 2013

Author Member

Yeah, the use case is to help the merchant make the buyflow simpler... to help them know what arguments they should pass to navigator.transact.pay().

This comment has been minimized.

Copy link
@dlongley

dlongley Jul 1, 2013

Member

Perhaps it can work more like this:

Prerequisite: The customer can set their own registered payment providers and an order of preference.

Scenario: The customer wants to buy something on a merchant's site. The merchant provides an ordered (by preference) list of payment providers to a navigator API call. The customer's browser looks through the customer's preferred providers for a match in the merchant's list and selects one if found (in order of preference). If no match is found, then the customer's browser notifies the customer that no common payment provider was found and it then takes the first payment provider from the merchant's list and asks the customer if they'd like to register with that provider.

This approach does a better job of keeping the customer's payment providers hidden from the merchant but still, I think, accomplishes the end goal of negotiating for a payment provider to make the purchase flow simpler.

This comment has been minimized.

Copy link
@kumar303

kumar303 Jul 2, 2013

Member

@dlongley yes, for this use case I see no need for getProviders. This case is one that we had in mind; the thought was to show a prompt asking which provider to select as part of the chrome UI before beginning the payment -- no UX works has been done on that yet for Firefox OS though. Because of the chrome prompt, the merchant would always pass all supported providers to mozPay.

Are there other cases that we need to think of?

This comment has been minimized.

Copy link
@msporny

msporny Jul 10, 2013

Author Member

I can't think of another case that we need to think of right now. I'll go ahead and make these changes to the spec and then we can change it if we find out that it's not flexible enough.

</p>

<dl class="parameters">
<dt>string[] query</dt>
<dd>
An array of payment provider types that are supported by the merchant.
</dd>
</dl>
</dd>
</dl>
</section> <!-- end of NavigatorPayment -->
</section>
Expand Down

1 comment on commit a0885d7

@msporny
Copy link
Member Author

@msporny msporny commented on a0885d7 Jul 1, 2013

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to #3 and #12.

Please sign in to comment.