Apps/WebApplicationReceipt: Difference between revisions
(Privacy changes) |
|||
Line 9: | Line 9: | ||
* <tt>typ</tt>: MUST be the string <tt>"purchase-receipt"</tt> | * <tt>typ</tt>: MUST be the string <tt>"purchase-receipt"</tt> | ||
* <tt>product</tt>: A JSON object identifying the product the receipt covers and any store specific data. | * <tt>product</tt>: A JSON object identifying the product the receipt covers and any store specific data. | ||
* <tt>user</tt>: A JSON object containing an | * <tt>user</tt>: A JSON object containing an identifier that the issuing store can use to identify the user associated with this receipt. | ||
* <tt>iss</tt>: A full domain (scheme, host, and port) for the store that issued the receipt | * <tt>iss</tt>: A full domain (scheme, host, and port) for the store that issued the receipt | ||
* <tt>nbf</tt>: A "not-before" timestamp (seconds from 1970-01-01T00:00:00Z in UTC, RFC3339), indicating when the purchase was completed | * <tt>nbf</tt>: A "not-before" timestamp (seconds from 1970-01-01T00:00:00Z in UTC, RFC3339), indicating when the purchase was completed | ||
Line 27: | Line 27: | ||
=== the user field === | === the user field === | ||
The <tt>user</tt> field provides an | The <tt>user</tt> field provides an identifier that the issuing store can use to identify the human user associated with this receipt. There is no requirement that any other actor be able to validate this field, or use its contents. It is a JSON object structure, containing the following fields: | ||
* <tt>type</tt>: A string | * <tt>type</tt>: A string | ||
* <tt>value</tt>: A string | * <tt>value</tt>: A string | ||
The default supported value of | The default supported value of <tt>type</tt> is <tt>directed-identifier</tt>, and <tt>value</tt> is a unique user ID. To protect user privacy, the <tt>user</tt> field should not be an email address, or another identifier that the user or anyone else might recognize. Instead, the suggested implementation is to randomly generate a GUID for each transaction. The store should retain the GUID, and use it to link receipts to accounts, but it should be an unusable opaque identifier to all others. | ||
=== the iss field === | === the iss field === | ||
Line 68: | Line 56: | ||
=== the verify field === | === the verify field === | ||
The <tt>verify</tt> field is a URL. | The <tt>verify</tt> field is a URL. Although this is strongly discouraged, it can be used for automated verification of a receipt by application receivers. See "Interaction with the verify URL", below. | ||
=== the reissue field === | === the reissue field === | ||
Line 83: | Line 71: | ||
}, | }, | ||
user: { | user: { | ||
type: " | type: "directed-identifier", | ||
value: " | value: "4fb35151-2b9b-4ba2-8283-c49d381640bd" | ||
}, | }, | ||
iss: "https://appstore.com", | iss: "https://appstore.com", | ||
Line 109: | Line 97: | ||
# Verifying the cryptographic integrity of the receipt itself | # Verifying the cryptographic integrity of the receipt itself | ||
# Authenticating the identity of the user presenting the receipt | # Authenticating the identity of the user presenting the receipt | ||
Checking the validity of the receipt with the issuer is strongly discouraged. | |||
Verifying the receipt is according to the usual rules of JWT verification. Public key discovery for the issuer is out of scope for JWT, but it is expected that verifying parties will receive public keys from their chosen payment providers through well-documented means, and that the <tt>iss</tt> field will be used to pick a public key from a previously-retrieved list. | Verifying the receipt is according to the usual rules of JWT verification. Public key discovery for the issuer is out of scope for JWT, but it is expected that verifying parties will receive public keys from their chosen payment providers through well-documented means, and that the <tt>iss</tt> field will be used to pick a public key from a previously-retrieved list. | ||
Line 119: | Line 108: | ||
=== Interaction with the <tt>verify</tt> URL === | === Interaction with the <tt>verify</tt> URL === | ||
If the <tt>verify</tt> URL is present, the receiving party may verify it by issuing a POST request to it, where the message body contains the complete receipt. | If the <tt>verify</tt> URL is present, the receiving party may verify it by issuing a POST request to it, where the message body contains the complete receipt. Note, however, that verifying a receipt using the verify URL is strongly discouraged for privacy reasons. Instead, applications should check the cryptographic validity of the receipt. | ||
The return value of this request is a JSON object with fields: | |||
* <tt>status</tt>: A string, containing one of the values "ok", "pending", "refunded", "expired" or "invalid". | * <tt>status</tt>: A string, containing one of the values "ok", "pending", "refunded", "expired" or "invalid". |
Revision as of 23:22, 17 August 2012
A Web Application Receipt is a portable, verifiable proof of purchase token. Receipts are created by payment services providers, distributed to clients, and verified by vendors of digital goods, content, and services.
The Web Application Receipt is implemented as a digitally-signed JSON data structure. This format is universally readable by clients and servers.
Data Fields
A receipt encodes an affirmation by a payment processor that a particular user has completed a transaction to acquire a particular digital product. It contains the following fields:
- typ: MUST be the string "purchase-receipt"
- product: A JSON object identifying the product the receipt covers and any store specific data.
- user: A JSON object containing an identifier that the issuing store can use to identify the user associated with this receipt.
- iss: A full domain (scheme, host, and port) for the store that issued the receipt
- nbf: A "not-before" timestamp (seconds from 1970-01-01T00:00:00Z in UTC, RFC3339), indicating when the purchase was completed
- iat: An "issued-at" timestamp (seconds from 1970-01-01T00:00:00Z in UTC, RFC3339), indicating when this receipt was issued
- exp: (optional) An "expiry" timestamp (seconds from 1970-01-01T00:00:00Z in UTC, RFC3339), indicating when this receipt will exipre
- detail: (optional) A URL that contains additional human- or machine-readable detail about the purchase
- verify: (optional) A URL that can be used by an authenticated application to verify a receipt
- reissue: (optional) A URL that can be used to re-issue a new receipt
the product field
The product field identifies the digital good whose sale is represented by the receipt. It is a JSON object structure, containing the following fields:
- url: A URL representing the root of a domain, without a trailing slash (e.g. "https://someapp.com"), is conventionally defined to represent "a web application"; URLs rooted further inside the site are conventionally defined to represent "in-application purchases", and can use whatever path scheme is convenient to the developer and issuer of the receipt.
- storedata: A string that uniquely identifies this app for the verifier of the receipt.
the user field
The user field provides an identifier that the issuing store can use to identify the human user associated with this receipt. There is no requirement that any other actor be able to validate this field, or use its contents. It is a JSON object structure, containing the following fields:
- type: A string
- value: A string
The default supported value of type is directed-identifier, and value is a unique user ID. To protect user privacy, the user field should not be an email address, or another identifier that the user or anyone else might recognize. Instead, the suggested implementation is to randomly generate a GUID for each transaction. The store should retain the GUID, and use it to link receipts to accounts, but it should be an unusable opaque identifier to all others.
the iss field
The iss field is the full domain of the issuer of the receipt. It must contain at least a scheme and host, separated by a colon and '//'. If the port on which the issuer receives traffic is non-standard (80 for HTTP, 443 for HTTPS), the port must be included following a ':' character. A trailing slash '/' is NOT included in the value.
the nbf field
The nbf (not before) field identifies the time before which the receipt MUST NOT be accepted for processing. The processing of the nbf field requires that the current date/time must be after or equal to the not-before date/time listed in the nbf field. Implementers may provide for some small leeway, usually no more than a few minutes, to account for clock skew.
the iat field
The iat (issued at) field identifies the time at which the receipt was issued. This claim can be used to determine the age of the token.
the exp field
The exp (expiry) field identifies the time at which the receipt will expire.
the detail field
The detail field is a URL. It is expected to resolve to a human-readable web page which contains detailed information about the receipt. If a transaction log or refund capability is provided for the purchase, it is expected that this page will contain those functions. The page may optionally contain machine-readable information about the transaction. (TODO: Identify microformats/microdata fields?)
the verify field
The verify field is a URL. Although this is strongly discouraged, it can be used for automated verification of a receipt by application receivers. See "Interaction with the verify URL", below.
the reissue field
The reissue field is a URL. Is is used for automated reissuing of receipts.
An example receipt
{ typ: "purchase-receipt", product: { url: "https://grumpybadgers.com", storedata: "5169314356" }, user: { type: "directed-identifier", value: "4fb35151-2b9b-4ba2-8283-c49d381640bd" }, iss: "https://appstore.com", nbf: 131360185, iat: 131360188, exp: 141360188, detail: "https://appstore.com/receipt/5169314356", verify: "https://appstore.com/verify/5169314356", reissue: "https://appstore.com/reissue/5169314356" }
Creation of the Digital Signature
As of this writing, the receipt is digitally signed by applying the JSON Web Token draft specification.
This specification may be superseded by the Javascript Object Signature and Encryption specification (JOSE), which is currently still in the discussion stages.
In JSON Web Token parlance, the typ, iss, nbf, and iat fields are Reserved Claims, and are subject to normal JWT processing rules.
Verification of a Receipt
Applications receiving a receipt are expected to verify it by:
- Verifying the cryptographic integrity of the receipt itself
- Authenticating the identity of the user presenting the receipt
Checking the validity of the receipt with the issuer is strongly discouraged.
Verifying the receipt is according to the usual rules of JWT verification. Public key discovery for the issuer is out of scope for JWT, but it is expected that verifying parties will receive public keys from their chosen payment providers through well-documented means, and that the iss field will be used to pick a public key from a previously-retrieved list.
Authentication of the user is dependent on the user identification contained in the user field. At this writing, the only supported user identification technique is a verified email address delivered through BrowserID. BrowserID-savvy application runtimes will use the BrowserID Directed Identity Assertion API to allow verifying parties to retrieve a user assertion without requiring a consent popup during application launch.
If a payment provider offers a verify URL in the receipt, the verifying party is allowed to query that URL to determine the real-time status of the receipt.
Interaction with the verify URL
If the verify URL is present, the receiving party may verify it by issuing a POST request to it, where the message body contains the complete receipt. Note, however, that verifying a receipt using the verify URL is strongly discouraged for privacy reasons. Instead, applications should check the cryptographic validity of the receipt.
The return value of this request is a JSON object with fields:
- status: A string, containing one of the values "ok", "pending", "refunded", "expired" or "invalid".
Application-level authentication on the verifyURL request is not strictly required, as the possession of a receipt proves that the application is already part of a trusted message flow.
Applications are free to re-query the verifyURL field as often as they see fit; whether this is a one-time or an every-time interaction, or something in between, is up to the application implementor to decide.
The verify URL will always return 200 for a successful check. Other possible response codes are 500 (server error) or a 503 (server busy). In the case of a 503, the client should retry at a later date. Clients should not assume that a 503 is a sign that the receipt is invalid.
References
- JSON Web Token
- RFC 3339: Date and Time on the Internet: Timestamps