Hi all.
We're rapidly approaching the day when third party app developers can begin testing web payments using navigator.mozPay() [1] against Mozilla's Web Payment Provider [2]. I'd like to get some feedback on ideas for how developers can *test* their use of the API.
[1]
https://wiki.mozilla.org/WebAPI/WebPayment
[2]
https://wiki.mozilla.org/WebAPI/WebPaymentProvider
Some info on those wiki pages is outdated already (fixes are coming). Here is a summary of how developers will set up payments:
The developer...
- submits app to Firefox Marketplace
- activates in-app payments
- enters bank details to receive money
- clicks a button to generate a secret key
- hosts an app on a server
- writes server code to sign JWTs (JSON Web Tokens) with the secret key
- hosts two URLs, a postback and a chargeback
- creates purchase button in app that calls nav.mozPay([signedJWT])
How does a developer test this? She will want to know:
1. Did I sign my JWT correctly, is the format OK, etc?
2. Are my postbacks and chargebacks hooked up correctly to my client code?
The second question is the most important because this is how the app developer protects against malicious attackers stealing digital goods. The postback needs to reconcile the product and probably also the user identity which would all be managed internally by the app.
Here is an example of constructing and signing a JWT request:
token = jwt.encode({
"iss" : appIdFromMarketplace,
"aud" : "
marketplace.firefox.com",
"typ" : "mozilla/payments/v1/pay",
"exp" : 1337357297,
"iat" : 1337360897,
"request" : {
"name" : "Unlock Level 10",
"description" : "The most exciting level in the game! Dungeons! Fire!",
"id": "unique-id-for-product",
"pricePoint": 1, // This might convert to USD 0.99, EUR 0.89, BRL 1.20
"productData" : "my_product_id=1234&my_user_id=345",
"postbackURL" : "
http://castlgame.com/payments/postback",
"chargebackURL" : "
http://castlegame.com/payments/chargeback"
}
}, secretKeyFromMarketplace)
The app fetches this JWT from the server and runs this JS code on the client when the user clicks buy:
var request = navigator.mozPay([signedJWT]);
request.onsuccess = function() {
// Poll the server, waiting for a successful postback...
};
request.onerror = function() {
console.log('Payment failed:',
this.error.name);
// more DOMRequest checking...
};
Note that these success/error handlers on the client are not as useful as the server side postback/chargeback handlers. The former is more for UI errors like the user clicking the Cancel button. In order to fulfill payment, the developer must use a postback handler so she can verify the JWT signature.
TEST PROPOSAL
The developer could test successful payments by amending a JWT like this:
{
...
"request" : {
"name" : "Unlock Level 10",
...
"simulate": {
"result": "postback"
},
}
}
That is, add a simulate option to the request that describes what to simulate. The above code would run against the same production server configured in shipping devices (and Firefox OS Simulator). When the server sees the simulate option it would never process any payment, it would simply say "Click this button to continue the simulation". In this case, that button would do a real postback to the app developer's server as if a real payment went through successfully. The developer could then test their product delivery mechanism without sending a real payment through. Since postbacks receive a copy of the original JWT then the dev could detect if it were a test via the simulate option.
To simulate an error, the option would be:
{
"request" : {
...
"simulate": {
"result": "chargeback",
"reason": "Insufficient funds"
},
}
}
Chargeback reasons aren't very well defined yet but this object model would allow us to add properties as needed in the future.
What are your thoughts on this? Either from the developer perspective, the server perspective, security-wise, etc. Would there be an easier or alternate way for developers to test payments?
One optimization is that we can require developers to generate a special secret key just for testing purposes. Thus the developer would not have to store a production key on their development/test server. The test key would only allow the simulate option and could never be used to process real payments.
thanks, Kumar