-
Notifications
You must be signed in to change notification settings - Fork 22
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
Signed transaction data object #342
Comments
Hi @senexi , can you confirm if you've signed an OpenID contribution agreement please, and if not sign one please? https://openid.net/intellectual-property/openid-foundation-contribution-agreements/ Thanks! |
Can you describe your requirement / use-case in a bit more detail? We already have the option to sign the Authorization Request containing the |
@jogu we are checking the paperwork today and sign it. |
@c2bo we are currently working on using this feature for payments where the presentation of a credential is requested by a merchant but will be forwarded to an issuing bank for verification. If the We will also publish a paper describing it in more details soon. Will link to it once it is published. |
@jogu I signed the agreement. |
Thanks @senexi ! Can you expand on this bit please:
A flow diagram might help as I'm not sure how the issuing bank and the merchant relate to the issuer/wallet/verifier roles in OID4VP. |
Hi @jogu Here it is explained in more detail. However the important part might be this. An sd-jwt presentation (named P2Pay here) is forwarded from the verifier to the issuer of the credential. And the issuer could verify who the originator of the transaction_data object actually is, if it would be signed. |
The current flow design is intended to be used by the ASPSP to authorize a transaction with its customer (through the wallet). That's why a payment credential (issued by the ASPSP) is used to do the authorization. Your flow is the typical Open Banking Payment Initiation flow, where the TPP gets an access token to initiate a payment with the ASPSP. I don't understand what the value/purpose of the TPP to wallet interaction is in this case. Can you please explain? Tp me it seems you want to utilize the credential presentation (with the transaction data) as kind of an access token towards the ASPSP. |
In the standard OpenBanking SCA Flow the customer is initiating the payment through a different channel first. But the actual initiation of the payment (including SCA) could also be done using the wallet, by requesting an attestation that links to a payment account an a certain payment method of rail. This also provides the option for the TPP / merchant to request additional attestations like age verification or a loyalty card and thereby leverage the wallet ecosystem. In this case, the presentation would be forwarded to the issuer for verification (and payment execution). For that case, it would be useful if the ASPSP could not only verify that the presentation is linked to a certain payment request (transaction_data object), but also that this payment request is linked to the TPP. |
Wouldn't the TPP be known to the ASPSP based on the interaction between them? Berlin Group etc. typically are not anonymous APIs; the TPP would have an API client id + secret / certificate of some sort in any case? |
@stefan-kauhaus yes, looking at open banking, the TPP is identified by the according certificates. However we are not only looking at open banking. If we look at it from a more generic point of view, we are talking about forwarding the presentation - may be even relaying it through multiple parties. So it might not always be the case, that the party submitting the presentation to the issuing ASPSP is the one who created the authorization request for the wallet. In such a case, a signed |
It is a bit hard to understand what the TPP adds to the pudding in the depicted scenario. If there is a Merchant involved, it needs to be included in the sequence diagram as well. In case a TPP forwards an authorization (like illustrated), I would assume that it would embed the received authorization data, in a specific TPP-signed TPP->ASPSP message. |
This is probably the motivation for signed |
Hi @senexi, this signature would only add value if the 'ultimate verifier' (in this example, the payer's PSP) has an understanding who the 'immediate RP' (the merchant/PISP/etc.) is and if he has a robust way to obtain that party's public key, right? How do you see this part? |
I am also slightly worried about privacy implications for this flow. Wouldn't we in the case that is depicted here want the TPP to not be able to see all details like account information? |
Hi all, I think the current proposal has some drawbacks.
I suggest to adopt a more Open Banking style approach and use the wallet to issue a sender constrained access token (which contains the payment VP). Note: the proposed OAuth flow uses the messages as designed for OpenID4VP, so it will require OAuth extensions (let's call it decentralized OAuth ;-)).
The request (step 4) would contain an authorization_details parameter with the following content: {
"type": "payment_initiation",
"instructedAmount": {
"currency": "EUR",
"amount": "123.50"
},
"creditorName": "Merchant A",
"creditorAccount": {
"bic":"ABCIDEFFXXX",
"iban": "DE02100100109307118603"
},
"remittanceInformationUnstructured": "Ref Number Merchant"
} It would also need to contain a proof of possession of a DPoP key, like this: {
"typ":"dpop+jwt",
"alg":"ES256",
"jwk": {
"kty":"EC",
"x":"l8tFrhx-34tV3hRICRDY9zCkDlpBhF42UQUfWVAWBFs",
"y":"9VE4jf_Ok_o64zbTTlcuNJajHmt6v9TDVrU0CdvGRDA",
"crv":"P-256"
}
}
.
{
"iat":1562262616,
"nonce": "eyJ7S_zG.eyJH0-Z.HX4w-7v"
} The wallet would need to know that such a request needs to be answered with an access token containing the presentation of an EAA of a certain type, lets assume a {
"iss": "https://issuer.eudiw.com",
"aud": "https://bank.example.com/api",
"exp": 1883000000,
"nbf": 1718198433,
"iat": 1718198433,
"a2pay_presentation": "eyJhbGciOiAiRVMy..V0~Wy..ZnBAan5g",
"cnf": {
"jwk": {
"kty":"EC",
"x":"l8tFrhx-34tV3hRICRDY9zCkDlpBhF42UQUfWVAWBFs",
"y":"9VE4jf_Ok_o64zbTTlcuNJajHmt6v9TDVrU0CdvGRDA",
"crv":"P-256"
}
}
} The TPP would need to send this access token along with the DPoP proof in step 11. WDYT? |
Thanx @tlodderstedt, this is AFAIK the first (ever) attempt by somebody representing OpenID, taking a stab at a wallet associated with Open Banking! Rather than going into the specification details, I believe we should first spend time figuring out what our expectations may be with respect to functionality, security, and privacy. None of the published pilots have bothered much with these rather fundamental issues. eIDAS or ARF compliance means little to the payment community. It is also worth keeping in mind that the competition is fierce and that the market is [rightfully] quite reluctant adopting unproven solutions. Making a slightly better mousetrap is of course an option, but that doesn't sound very cool. There is plenty of room for innovation since Apple Pay does currently not support the following: Regarding the specifications themselves, I have a hard time figuring out where the Merchants are. Merchants are neither relying parties, nor in need of credential presentations; they depend on assurances that they will be (or are already being) paid. Such data can only be provided by payment backends. In the rare occasion a Merchant is also a TPP, it shouldn't change anything protocol-wise; it just means taking on multiple roles. |
@tlodderstedt, thanks for picking this up. A few remarks regarding the proposal. As you already mentioned, wrapping the P2Pay in an Access token introduces a new / custom flow for the wallet. Although we also included a proposal for a possible endpoint (A2Pay Direct) where a bank could directly receive a P2Pay, we always envisioned it as something optional as there might be many different / proprietary ways to transport the P2Pay in the end. For example, the signed body feature in the current Berlin Group specs might also be a viable option. Taking this into account, it would mean introducing a specific frontend flow (for all wallets) only to support one possible backend flow, wouldn’t it? But wouldn’t it be possible to keep the default OpenID4VP flow and tackle the drawbacks you mentioned in a different way. Couldn’t the ASPSP easily detect a replay by tracking the hash of the P2Pay? Once a P2Pay is processed, the ASPSP would refuse the processing if it would be submitted again. To limit the timespan the ASPSP needs to keep track of the P2Pay hash, the lifetime of the according KB-JWT could be limited by including the Also sharing the claims of the A2Pay with the TPP might not really be an issue, as the A2Pay should contain only information that actually need to be shared with the TPP. Like some kind of an account identifier and / or meta data required for processing by the payment rail that the A2Pay is connected with. Also wouldn't the TPP always be able to see those claims. What we are currently not able to do is, to keep the link between the original TPP (who presented the payment request to the user) and the P2Pay. Although it might not even be required (depending on the payment rail), it would be useful to have the option to keep this link cryptographically - which is why I submitted this feature request here ;-) If the TPP is actually signing the transaction_data object, it would establish this hard link between the wallet signed P2Pay and the TPP, no matter how the P2Pay is relayed to the issuer in the end. |
Would you maybe care to share some details and explain in which way the LSPs never looked at privacy and security? It is actually a bold statement, considering the fact that the flow proposed by the LSP completely builds on the default OpenID4VP flow for SCA. But maybe there is an issue there… Regarding the merchant. In this model, the role of the merchant and TPP are the same - as you noticed already. And yes, it should not change anything protocol wise. |
@senexi Pardon me for using somewhat sweeping comments.
Yes, because these specifications do assumptions that doesn't seem to translate well to consumer-to-business payment transactions.
Well, this was not my intention. Merchants and TPPs represent entities having distinct roles as well as unique security, privacy and trust characteristics. That a single entity can take on multiple roles is another thing. |
@senexi wrote:
Yes! This is idempotent operation and may even contribute to reliability since it makes retransmission a "thing": |
When we use transaction_data to address the dynamic linking requirement, then the data in this object has the purpose of being shared knowledge between the user (payer), the user's bank (payer's PSP), and the recipient (payee, e.g. merchant, potentially represented by their acquirer or PISP). The data typically contains the amount, currency, and payee details (including their name and/or account number). The data typically does not contain any payer's details (like payer's name or account number), as this is established separately between payer and payer's PSP. Hence, the only data being at risk of getting disseminated when additional intermediaries are added to the picture (to help "forwarding" the authentication/dynamic linking evidence to the payer's PSP, as @senexi explained) are the merchant's details. Given it is the merchant who would hand this off to the intermediary, I do not see specific privacy implications. |
@stefan-kauhaus Since there is no fifth entity (Merchant/Payee) in the depicted schemes, I'm unable to draw any conclusions regarding privacy with respect to the User/Payer. |
My comments addressed @c2bo's question on privacy against the backdrop of the scenario how @senexi had sketched it:
|
@stefan-kauhaus I see. Personally, I have some difficulties translating the above into a concrete specification. |
A Sequence Diagram with Merchant/Payee https://cyberphone.github.io/doc/defensive-publications/partial-encryption-full-signature.pdf A simplified next step for the scheme described in the PDF adapted for SEPA:
|
@senexi one time use for replay detection is a rather limited approach as injections and any sort of abuse where the attacker prevents the legitimate party to use the token cannot be prevented. So if we want to make this additional flow a secure option of the normal OpenID4VP flow, we need additional measures in place. The difference between normal OpenID4VP and this flow is the fact the RP does not consume the credential presentation itself but rather uses it to authorize an API call with a 3rd party. I suggest to signal this to the wallet in the presentation request through an additional parameter
This is an example request for step 4: {
"client_id": "x509_san_dns:client.psp.org",
"response_type": "vp_token",
"redirect_uri": "https://client.psp.org/callback",
"nonce": "n-0S6_WzA2Mj",
"dcql_query": {
"credentials": [
{
"id": "A2Pay",
"format": "dc+sd-jwt",
"meta": {
"vct_values": [
"https://credentials.example.com/a2pay"
]
},
"claims": [
{"path": ["id"]},
{"path": ["payment-product"]},
{"path": ["payment-uri"]},
{"path": ["currency"]},
{"path": ["name"]}
]
}
]
},
"transaction_data": [
eyAidHlwZSI6IC...cGluZyBhdCBNZXJjaGFudCBBIiB9
],
"present_to_thirdparty": {
"credential_ids": [
"A2Pay"
],
"dpop_key": {
"jwk": {
"crv": "P-256",
"kty": "EC",
"x": "NASJ2ADuagOvraLf7O4VxcBMbantzL9dd0jpvMLnBfs",
"y": "OJY6pqCqRIzpEt78OXasWHGgqV5ZGre_3cHtpNH82gg"
}
}
}
} The parameter
Note: the The wallet will ask the user for consent for the transaction and produce the response. The wallet will wrap the respective credential presentation into an JWT-based access token along with a {
"iss": "https://issuer.eudiw.com",
"aud": "https://bank.example.com",
"client_id": "x509_san_dns:client.psp.org",
"exp": 1883000000,
"nbf": 1718198433,
"iat": 1718198433,
"credential_presentation": "eyJhbGciOiAiRVMy..V0~Wy..ZnBAan5g",
"cnf": {
"jwk": {
"kty":"EC",
"x":"l8tFrhx-34tV3hRICRDY9zCkDlpBhF42UQUfWVAWBFs",
"y":"9VE4jf_Ok_o64zbTTlcuNJajHmt6v9TDVrU0CdvGRDA",
"crv":"P-256"
}
}
} Note: Even though the access token uses the JWT-format, this design is intended to work with any credential format. This access token is signed with the same key that is used to sign the credential presentation. The access token is encrypted with a public key of the bank. This key would need to be determined either from data in the A2Pay credential or through metadata the wallet requests from the bank. The access token is returned in the
Here is an example: {
"vp_token": {
"A2Pay": {
"access_token": eyJhbGciOi...00ifQ.OKOaw...zg.48...3b.5eym8T...QD_A.XFBo...SkQ,
"nonce": "n-0S6_WzA2Mj",
"metadata": {
"payment-uri": "https://bank.example.com/pay/7dfe5484g78"
}
}
}
} Note: depending on the use case, the RP might know the API to send the access token to in advance. In such cases, the RP would add them to the The RP will send this access token along with the DPoP proof in step 11. |
@tlodderstedt thanks for your proposal. I can see us going forward with that as it is also a more explicit way to handle things. One thing that comes to my mind though is how to determine the |
@tlodderstedt @senexi C2B (Consumer To Business) payment schemes are (usually) Merchant-centric but I don't see any Merchant. That I also can't find a description of payment credentials makes it hard to see if your specifications matches or surpasses the feature list that I (FWIW...) consider required. Regarding stealing payer authorizations, there are essentially two basic ways:
Regarding the latter, the "Saturn" wallet builds on the same (but inverted) security model as FIDO: WebPKI-secured host-names. That is, the Wallet records the request host name and provides as a part of the authorization data. Then the PSP based on registered host name information + strong Merchant authentication (via a signature/id), can verify if the forwarded request is authentic. Checking claimed name is another easy to perform test.
It is also worth considering that in order to be Merchant you (probably) have to sign a compliance agreement. This makes it somewhat less attractive committing crimes in full daylight. The UX described in https://github.com/nobid-consortium/payment-reference-documentation/blob/main/payment-reference-doc.md#screenflow feels a bit "quirky". A single user Authz should be sufficient. |
@senexi happy you like the proposal ;-)
I have considered to add this to the credential through claims and/or (disclosure) policies. If that is to static, one could also use issuer hosted metadata. |
@cyberphone don't you think the PSP could be a merchant? |
Well, Merchants and PSPs represent different roles. In some cases an entity takes on both roles. I don't see a need for doing something special protocol-wise for edge cases. I guess that possible optimizations and simplifications can be carried out locally. |
According to https://github.com/nobid-consortium/payment-reference-documentation/blob/main/payment-reference-doc.md#security-considerations Merchants are TPPs that verify. Verify what? These guys have another idea on how to use OpenID4VP: Facts:
Any ideas on how to proceed? |
@cyberphone We just synconized with EWC 48hs ago and they are very much aligned to this proposal. We both sync regularly. |
@cyberphone Merchandts verify age e.g., shipping adresses @cyberphone Why don't you join one of the parties in NOBID or EWC to contribute directly and get a very deep insight into the current software developments? |
And the the LSPs are part of the ATAG. |
And it was from my perspective the wrong question at the SPRIND conference. This approach is not to compete against Apple, Google, Mastercard or Visa. Ideas how to proceed. Very clear.
|
As stated in the document: "verification of the P2Pay". In case you are asking what a P2Pay is... it is explained in the document.
Seriously? Do you actually read these documents? Maybe you would notice that they are quite similar.... But I would like to focus on the actual issue and proposal from @tlodderstedt here... Regarding the metadata, I think it absolutely makes sense to move some of the claims from the credential to the PSP / Issuers metadata, as they are the same for every issued credential. Making the approach more flexible and reducing the static data within the credential. @stefan-kauhaus also pointed out that option. |
Personally, I don't see much point in developing a system that doesn't have these characteristics. The system I'm working with (entirely on my own and without any funding 😪), is explicitly designed for competitiveness.
Yes, but this is unrelated to payments.
I believe I did but I got no response. Anyway, without clearly separating Merchants and TPPs, I wouldn't consider joining the party. |
I think being explicit that this flow (whatever it will look like) is intended to be shown to / used with a third party would be a very good idea here -> +1 on the |
@c2bo This is implicit in other payment authorization systems. Maybe the idea is that a single wallet implementation, should be able to handle everything from age-assertions to payments? This would IMO be a pretty bad idea. My guess is that Apple have a common code-base for certain functions like crypto, but that the wallet dispatches requests to application-specific "executors". Anyway, a unified flow seems pretty distant since we (apparently) have quite different ideas about what a Merchant is. In the depicted schemes, Merchants would either need to have contracts with all issuer banks or be accredited by an NCA (National Competent Agency) as an PSD2 entity. This obviously doesn't apply to the coffee shop on the corner. There is a reason to why companies like Adyen, Stripe, Worldline exists. They handle millions of Merchants and thousands of Banks. There ARE ways to change this but this require a major architectural update. I'm currently not actively pushing this but it might be interesting to see anyway... The idea is quite simple: The Merchant's Bank maintains a Trust Service (TS) holding core Merchant data like name, public key, account, etc. With this, the User Bank can verify the authenticity of Merchant requests through simple lookups. The Merchant data is in turn signed a by key+certificate belonging to a bank PKI. The very same PKI is also used for returning authoritative responses to Merchants that requests have been processed. My take on the Wallet depends on trust services also in a more conventional setup. That is, the ARF doesn't apply. This is not a theory: https://test.webpki.org/saturn-payeebank/ |
@tlodderstedt @senexi @mobinauten The bigger question (IMO...) is if we believe we are creating a standard for an EUDI Wallet with payment functionality. I don't think we are even close because we haven't yet concluded what our expectations are. Such a standard would also have to (in order to be "authoritative") be developed by a standards committee. OpenID does currently not have a "Payment Wallet WG". Is this a problem? Yes, the lack of a real standard will undoubtedly stall large-scale deployments unless one of the initiatives will considered a clear winner. Personally (FWIW), I have limited faith in Berlin Group's take on how to support payment wallets which caused me to develop an entirely different solution. Currently it is just "slideware", but I actually did a similar solution with a real bank back in 2019, and it worked pretty well. The main points with this concept are:
|
@senexi: To offer another perspective on the original topic: The KB JWT contains
(https://openid.net/specs/openid-4-verifiable-presentations-1_0.html#appendix-B.4.5-10) In our scenario, the 'Verifier' would be the immediate RP the presents to, and the KB JWT will reach the 'ultimate verifier' as well. So, the wallet already records who it is talking to and signs over this. Would this not be good enough as a solution (for now)? |
I don't suggest to standardize the use of wallets (or oid4vp) for payments at OIDF. I rather suggest to build the rails into oid4vp to enable use cases like payment authorization (and qes authorization). Having said that, we need concrete use cases here to be able to have a meaningful discussion. That's why it makes sense to use payments as example to drive the discussion. |
Indeed, we should differentiate between the enabling infrastructure and the payment mean and architecture as well. Different layers. |
Maybe we could take a step back and define a place for the Merchant? In my take on payment authorizations (which predates OpenID4VP with 8 years or so), the wallet is entirely unaware of rails and specific payment networks, it is just a fairly simple Merchant payment request-response scheme. There are no credential presentations or verifications either; with respect to the Merchant, the wallet response only provides core data needed for payment network and bank selection. It is not clear to me what more specifically an SDO would do. Define the content of Current specifications also need to be tested before any meaningful standardization can be performed. We are probably talking 2030 before such a standard would be ready (and probably already obsolete). |
@cyberphone We're testing these approaches since more than 12 months in LSPs NOBID and EWC. You should really join one of those a the coming ones to get deeper insights. |
Dear @mobinauten No one doubts that your stuff works. My questions are related to scalability and architecture.
At this stage I prefer sticking to the publicly available documents. I'm sort of a spec. nerd. 😆. EWC seems to also target 3D Secure, something I would never consider since it is already available, albeit (typically) through mobile banking applications. SDO is short for Standards Development Organization. FWIW, I have limited faith in Berlin group's Signed Payment Request. Their single-level "monster" API concept, makes development and testing a nightmare! It is not very clear to me what mission SD-JWT could have in a payment authorization scheme. Cheers Anders |
Currently the
transaction_data
object is defined as a "base64url encoded JSON object". For some use-cases it might be useful to actually sign this data, so it can later be linked to its originator. So the idea would be to also allow an encoded JWT here.The text was updated successfully, but these errors were encountered: