Support is requested for 3D Secure 2.

Brtaintree overview is here: https://www.braintreepayments.com/blog/ready-for-3d-secure-2-0
Braintree documentation is here: https://developers.braintreepayments.com/guides/3d-secure/overview

Current status:

The current patch #47 works for both logged-in and anonymous users, for both initial transactions with a payment method and subsequent transactions with a stored payment method.

Summary of current progress:

Must do:
Fixed: Fix for logged-in non-guest checkout

Should do:
The verifyCard call should have the customer email address provided in hosted-fields-3ds.js
The verifyCard call should have the customer billing telephone number provided in hosted-fields-3ds.js
(See the Braintree docs)

CommentFileSizeAuthor
#99 interdiff_97-99.txt1.87 KBjsacksick
#99 3012225-99.patch24.1 KBjsacksick
#98 interdiff_96-97.txt10.64 KBjsacksick
#97 3012225-97.patch24.24 KBjsacksick
#97 3012225-97.patch24.24 KBjsacksick
#96 interdiff_89-96.txt31.14 KBjsacksick
#96 3012225-96.patch26.25 KBjsacksick
#89 interdiff-3012225-85-89.txt2.32 KBlisastreeter
#89 braintree_3ds2-3012225-89.patch51.73 KBlisastreeter
#87 braintree_3ds2-3012225-85.patch50.83 KBluksak
#86 interdiff-3012225-81-85.txt828 bytesluksak
#81 interdiff-3012225-79-81.txt3.11 KBlisastreeter
#81 interdiff-3012225-77-81.txt7.85 KBlisastreeter
#81 braintree_3ds2-3012225-81.patch51.31 KBlisastreeter
#80 interdiff-3012225-78-79.txt3.72 KBlisastreeter
#80 interdiff-3012225-77-79.txt5.69 KBlisastreeter
#79 interdiff-3012225-78-79.patch3.72 KBlisastreeter
#79 interdiff-3012225-77-79.patch5.69 KBlisastreeter
#79 braintree_3ds2-3012225-79.patch50.65 KBlisastreeter
#78 braintree_3ds2-3012225-78.patch51.08 KBlisastreeter
#78 interdiff-3012225-77-78.txt3.5 KBlisastreeter
#77 braintree_3ds2-3012225-77.patch50.71 KBlisastreeter
#72 braintree_3ds2-3012225-72.patch52.88 KBsittard
#71 braintree_3ds2-3012225-71.patch51.69 KBsittard
#68 braintree_3ds2-3012225-68.patch51.74 KBmartijn de wit
#67 braintree_3ds2-3012225-67.patch52.62 KBmartijn de wit
#66 braintree_3ds2-3012225-66.patch52.45 KBmartijn de wit
#64 interdiff-3012225-60-64.txt3.11 KBlisastreeter
#64 braintree_3ds2-3012225-64.patch51.19 KBlisastreeter
#60 interdiff-3012225-56-60.txt5.17 KBlisastreeter
#60 braintree_3ds2-3012225-60.patch51.88 KBlisastreeter
#56 braintree_3ds2-3012225-56.patch49.73 KBlisastreeter
#56 interdiff-3012225-47-56.txt4.12 KBlisastreeter
#49 braintree_3ds2-3012225-47.patch48.74 KBlisastreeter
#49 interdiff-3012225-46-47.txt7.02 KBlisastreeter
#46 interdiff-3012225-45-46.txt22.23 KBlisastreeter
#31 braintree_3ds2-3012225-30.patch20.34 KBsittard
#46 braintree_3ds2-3012225-46.patch47.85 KBlisastreeter
#15 braintree_3ds-3012225-15.patch17.05 KBlisastreeter
#45 interdiff-3012225-41-45.txt26.54 KBlisastreeter
#27 braintree_3ds2-3012225-27.patch19.39 KBalanhdev
#45 braintree_3ds2-3012225-45.patch45.37 KBlisastreeter
#13 braintree_3ds-3012225-13.patch17.12 KBlisastreeter
#41 interdiff-3012225-30-41.txt3.72 KBalanhdev
#15 interdiff-3012225-13-15.txt5.06 KBlisastreeter
#41 braintree_3ds2-3012225-41.patch20.39 KBalanhdev

Comments

sittard created an issue. See original summary.

bojanz’s picture

Adding related Commerce issue.

luksak’s picture

Braintree just sent out this mail to customers:

You've likely heard about Strong Customer Authentication (SCA) requirements, which are part of the Payment Services Directive (PSD2) regulations that came into effect early last year. We understand that there's a lot of uncertainty around these changes, so we wanted to reach out to help you begin to prepare.

What does SCA mandate?

SCA mandates that many transactions will need to be carried out more securely using at least two of these three authentication factors:

  • Knowledge: Something you know, typically a password or PIN.
  • Possession: Something you have, such as a device or credit card.
  • Inherence: Something you are physically, typically a fingerprint or other biometric.

What do I need to do?

Moving to 3D Secure 2.0 (3DS 2.0) can help merchants transacting in Europe meet SCA requirements as well as help enhance fraud protection. 3DS 2.0 is also expected to reduce friction in both the web- and mobile-purchase process and can help increase conversions.

When is the deadline?

Although the date of enforcement isn't until September 2019, Braintree recommends that merchants be ready to integrate 3DS 2.0 into their checkout experience by April 2019 per the card brands' guidelines.

What is the plan regarding 3DS 2.0?

scotwith1t’s picture

Also need a plan for a client regarding 3DS/PSD2 jazz. Thanks for any update!

bojanz’s picture

Nobody has offered to sponsor 3DS 2.0 so far, so there is no plan.
The Commerce Guys R&D resources are already assigned to other initiatives for Q1 2019.
So, possibly may/june, but no guarantees yet.

luksak’s picture

@bojanz thank you for the update! Could Braintree sponsor this?

bojanz’s picture

I will reach out to them and keep you updated.

sittard’s picture

Although we have until September 2019 to comply Braintree recommends that merchants be ready to integrate 3DS 2.0 into their checkout experience by April 2019. Therefore any chance this could be implemented sooner than May / June?

See also: https://www.braintreepayments.com/blog/ready-for-3d-secure-2-0/

Thanks.

bbuchert’s picture

bojanz’s picture

We have been able to secure funding.

The delivery date (Commerce & Braintree releases) is May 1st.
Work will start in March, with the goal of delivering initial results by April, but we can't guarantee completeness or stability at that point.

scotwith1t’s picture

That's great news!! Any chance there will also be a back port for D7, ideally in the same timeframe? :-/

bojanz’s picture

You would need to ask andyg5000, he develops and maintains the D7 branch, not Commerce Guys.
The issue for that is #2496627: Support 3D Secure.

lisastreeter’s picture

StatusFileSize
new17.12 KB

The payment gateway configuration setting for "3 D Secure" has three options: Disabled, Enabled, and Required.

When 3DS is enabled in normal/enabled mode, payments are accepted whenever liability is shifted. They are rejected when liability is NOT shifted but liability shift IS possible. In all other cases, the customer is not enrolled in 3DS so liability shift is not possible, and payments are accepted.

If 3DS is configured in strict/required mode, payments are only accepted when liability is shifted. Customers must be enrolled to make a payment and complete checkout.

For information on why certain 3DS result statuses are rejected/accepted, see https://developers.braintreepayments.com/guides/3d-secure/server-side/php

bojanz’s picture

Title: 3D Secure » Add support for 3D Secure 2.0
Status: Active » Needs review

Thanks, Lisa!

Updating status.

lisastreeter’s picture

StatusFileSize
new17.05 KB
new5.06 KB

Previous patch didn't apply. Hopefully this one will.

Also, this updated patch changes "three_d" to "3d" and updates Braintree 3Ds library version from 3.31.0 to 3.43.0.

mglaman’s picture

Status: Needs review » Needs work
+++ b/src/PluginForm/HostedFields/PaymentMethodAddForm.php
@@ -61,8 +67,28 @@ class PaymentMethodAddForm extends BasePaymentMethodAddForm {
+    $amount = 0;
+    if (!empty($configuration['3d_secure']) && $order = $this->routeMatch->getParameter('commerce_order')) {
+      // @todo should this be rounded?
+      $amount = $order->getBalance()->getNumber();
+    }

This will not work against the latest 2.x as the route match is no longer injected.

sittard’s picture

Many thanks for all the hard work on this feature it's looking good. How close are we to a release on this feature. Comments above suggest that the delivery date (Commerce & Braintree releases) was May 1st.

Thanks.

ashley george’s picture

Subscribing

luksak’s picture

@Ashley George please do not subscribe using a comment. You can use the "Follow" link in the right column at the top.

kristofferrom’s picture

Anyone has plans to do this for the D7-version too?

mglaman’s picture

Anyone has plans to do this for the D7-version too?

We can backport to 7.x once built for 8.x; once the lessons are learned it will be possible.

scotwith1t’s picture

D7 issue is here, just FYI #2496627: Support 3D Secure

sittard’s picture

Testing with patch #13 and #15 and I'm getting the following error when I click the 'Continue to Review' button on the checkout page:

The website encountered an unexpected error. Please try again later.</br></br><em class="placeholder">InvalidArgumentException</em>: $payment_details must contain the payment_method_nonce key. in <em class="placeholder">Drupal\commerce_braintree\Plugin\Commerce\PaymentGateway\HostedFields-&gt;createPaymentMethod()</em> (line <em class="placeholder">309</em> of <em class="placeholder">modules/contrib/commerce_braintree/src/Plugin/Commerce/PaymentGateway/HostedFields.php</em>). <pre class="backtrace">Drupal\commerce_payment\PluginForm\PaymentMethodAddForm-&gt;submitConfigurationForm(Array, Object) (Line: 150)

Any ideas? Thanks

sittard’s picture

Realised my error, I was attempting to apply the patch against 8.x-1.1 release and not the latest development branch. Can confirm that patch #15 does apply and works as expected with Commerce 8.x-2.11.

Thanks.

alanhdev’s picture

According to the implementation guide in the Braintree docs here, 3DS 2 support requires version 3.47.0 or higher of the Javascript V3 SDK. However, with patch #15 applied, the libraries loaded are only 3.43.0. According to Braintree docs here, there are new parameters for verify card calls which require the updated SDK.

I could re-roll the patch to update the JS SDK library versions, but there are other issues. For instance, the version is not being specified in braintree.threeDSecure.create as per the docs here meaning that the 3DS 2 protocol isn't being used.

The current Braintree PHP SDK version is 4.2.0 (which also requires PHP 7.2.x). The dependency in the modules's composer.json results in installation of 3.40.

Is anyone actively working on this and, if so, any success using the older PHP library?

bojanz’s picture

Yikes. It's way too early for us to require people to have PHP 7.2. Both 7.0 and 7.1 would have been fine, but 7.2 is still very new.
We need to see if we can get 3DS working with the old SDK (3.4).
If not, we'll need to start notifying people immediately (about the impending requirements change).

alanhdev’s picture

StatusFileSize
new19.39 KB

Okay, here is what I have so far adding 3DS2 to the existing patch #15.

  • Updated the Braintree JS libraries to the latest version (3.50.1) to provide the 3DS2 functionality
  • Reworked the hosted-fields-3ds.js as per the Braintree docs
  • Ran tests with successful and failing verification on a vanilla Commerce install

The old Braintree 3.x PHP libraries seem to be functional meaning an upgrade to 4.x and a requirement of PHP 7.2 is not necessary.

Still to do
The verifyCard call needs to have the billing address provided and ideally email address and telephone number too. I've marked this as todo in the hosted-fields-3ds.js file. The billing info is currently pulled directly from the form fields which isn't pretty or robust so that could do with some work.

Patch attached.

sittard’s picture

Testing with patch #27 (thank you).

Looks good but I noticed that the styling on error messages has disappeared. The commerce_braintree.libraries.yml needs the classy/message dependency added to the hosted-fields-3ds.

As follows:

hosted-fields-3ds:
  version: VERSION
  css:
    theme:
      css/commerce_braintree.form.css: {}
  js:
    js/hosted-fields-3ds.js: {}
    js/commerce_braintree.js: {}
  dependencies:
    - classy/messages
    - core/drupal.dialog
    - commerce_braintree/braintree-hosted-fields
    - commerce_braintree/braintree-3d-secure

Sorry not enough time to re-work the patch.

martijn de wit’s picture

Yikes. It's way too early for us to require people to have PHP 7.2. Both 7.0 and 7.1 would have been fine, but 7.2 is still very new.
We need to see if we can get 3DS working with the old SDK (3.4).

Is it an option to support both with a setting or a different sub-module structure?

sittard’s picture

OK I've had a go at updating the patch #27 (think this is my second or third patch - so hopefully works).

The patch now includes:
- Missing classy/message dependency
- Improvements to UX to scroll error message into view

Also I noticed during testing that the AMEX card was not valid but also did not provide user with an error so I've added some code to display the default 3D error messages to user. See also: https://braintree.github.io/braintree-web/current/three-d-secure_shared_....

@martin I think we are OK with PHP 7.1 requirement please see comments:
https://www.drupal.org/project/commerce_braintree/issues/3012225#comment...

The old Braintree 3.x PHP libraries seem to be functional meaning an upgrade to 4.x and a requirement of PHP 7.2 is not necessary.

sittard’s picture

martijn de wit’s picture

Status: Needs work » Needs review

status change to trigger the tests.

Sorry had not read that comment well. Than it seems no problem :)

sittard’s picture

The AMEX test cards (https://developers.braintreepayments.com/guides/3d-secure/testing-go-liv...) don't work with this patch. You will get the client error 'The data passed in `verifyCard` did not pass validation checks. See details for more info'

We've spoken to BrainTree and we may need to implement Amex safe key (for US Merchants).
See: https://developers.braintreepayments.com/guides/3d-secure/configuration#...

alanhdev’s picture

The error message object returned by verifyCard has a more helpful error nested further in.

Instead of this in the hosted-fields-3ds.js ...
message = that.errorMsg(verifyCardError);

...using something like this will give a nicer message about the card not being supported:

try {
  message = t("Error: ") + verifyCardError.details.originalError.details.originalError.error.message;
}
catch (e) {
  message = that.errorMsg(verifyCardError);
}
alanhdev’s picture

I've been testing this on a minimal sandbox install rather than a local copy of our client's dev site and I think there may be an issue with the saved payment method approach which is tripping up the 3DS2 process.

We have implemented a custom guest checkout on the client site which sets the payment method to non-reusable. For those transactions, everything looks good and the 3DS2 verification can be seen in the Braintree sandbox reports.

However, this isn't happening for authorised users and on the sandbox install. With the patch, the 3DS2 verification is called so you see the 3DS2 popup and this will allow a decline or authorisation at this point, but there is no reference to 3DS2 verification on the Braintree sandbox following a successful transaction. I suspect that is due to the payment method being saved and then used for the transaction.

The braintree docs here may be relevant: https://developers.braintreepayments.com/guides/3d-secure/migration/java...(mit)

sittard’s picture

If you can you let me know which BrainTree report shows the 3DS2 verification I can check it out in my Sandbox Account.

The other oddity that I've noticed on my Sandbox account under:
Settings > Business > Merchant Account > Account Details (click on an ID)

Under 3D Secure 2.0 it says:
Coming Soon! Learn more about 3DSecure 2.0

Which would suggest that my account is not accepting 3D Secure...

alanhdev’s picture

Ours also says coming soon but it's accepting 3DS2 transactions.

If you go to Transactions and search for your test transaction, a successful 3DS2 transaction should show a section like this:
3D Secure Information
EnrolledEnrolled (Y)
StatusAuthenticate attempt successful
3DS Version 2.1.0
Liability Shifted true
Liability Shift Possible true

However, I'm only seeing that for non-reusable payment methods (anonymous users) on the custom client checkout. Any created on the sandbox Drupal install resulting in a saved reusable payment method have no reference to 3DS2.

sittard’s picture

Many thanks I'm not seeing the reference to 3DS2 in any of my test transactions.

So I think your concerns are correct saved reusable payment method as provided by this patch have no 3DS2 verification ;(

alanhdev’s picture

If the payment method is set to non-reusable in the createPaymentMethod method in src/Plugin/Commerce/PaymentGateway/HostedFields.php createPaymentMethod, you should see the 3DS2 validation info. I've done this for testing by adding this to the start of the method:

$payment_method->setReusable(FALSE);
alanhdev’s picture

Status: Needs review » Needs work
alanhdev’s picture

StatusFileSize
new20.39 KB
new3.72 KB

Re-rolled the patch against the latest dev commit #f9395ca with the following changes:

  • Updated to latest JS libraries
  • Removed erroneous PATCHES.txt
  • Added a change to mark payment method as not reusable for anonymous users

Using this patch, transactions for anonymous guests correctly show the 3DS2 information in the Braintree sandbox. However, it doesn't for logged-in users as per comment #35 so work still needed.

alanhdev’s picture

Issue summary: View changes

Updated issue description with the current status.

lisastreeter’s picture

I've been working on, "Transactions for logged-in non-guest checkout are not showing that 3DS 2 is being used." Haven't made much progress, but here's an overview of what's happening.

3DS verification is being properly applied to cards entered by both guest and logged-in users. If the validation fails, the proper exceptions are thrown. On success, a valid payment method nonce is generated, which is a single-use token.

In the case of guest users, we set the "remote ID" of the payment method with the value of the payment method nonce. Then we use that payment method nonce to create the payment. The transaction shows in the Braintree control panel with all the 3DS information.

In the case of logged-in users, we use that payment method nonce to create a payment method stored on Braintree ("vaulted"). After using the nonce for that transaction, we need to generate a new nonce for the actual sale transaction. So we do that in the createPayment method:

$result = $this->api->paymentMethodNonce()->create($payment_method->getRemoteId());
$transaction_data['paymentMethodNonce'] = $result->paymentMethodNonce->nonce;

This new nonce is valid; if it weren't, the sale transaction wouldn't go through successfully. It does, BUT for this sale transaction, the 3DS information does not show up in the Braintree control panel. I do not know why this is the case. The credit card entered by the logged-in customer is just as fully verified as 3DS as the same credit card for the guest user. After going through the API documentation and reviewing our code in great detail, I'm wondering if this is just a UI error on Braintree's side. It seems like they're either not storing or not reporting on the 3DS status of vaulted credit cards so that when those cards are subsequently used (as is happening here), the 3DS info does not display in the control panel.

lisastreeter’s picture

I've received a response from Braintree support regarding our issue here. It looks like we're going to have an issue with stored payment methods and 3D secure. Here is the information I've received. (The "second scenario" he refers to is what we're seeing when we create a reusable payment method, store it on Braintree, and then create a sale transaction with the nonce generated from that payment method.)

The reason you are unable to see 3D Secure information in the transaction details of the second scenario you have posed, is because 3DS information does not get vaulted with the payment method token. 3D Secure nonces can only be used inTransaction.sale()​, Subscription.create()​, and Subscription.update()​ calls. The 3D Secure information is carried via the nonce, which is consumed once the task is complete. So if you authenticate via 3D Secure and do not use it in transaction, the 3D Secure information is lost.

There are two options you can explore here when it comes to vaulting cards with your 3D Secure flow:

1. Authenticate with 3D Secure, use the nonce in a transaction request, specify the option store_in_vault_on_success as true. This will process the transaction with 3D Secure and successfully store the payment method.

2. Store the card in the Vault first by using PaymentMethod.create()​, generate a nonce from the resulting payment method token, authenticate with 3D Secure, and use the 3DS-enriched nonce in the subsequent Transaction.sale()​ call. This method is best suited for when a customer saves their card information, but will not be making a purchase until a later time.

I haven't looked into that store_in_vault_on_success option yet, but it seems like that _could_ work. We just wouldn't create the remote payment method until after the payment is posted. But... then we still have a problem when a customer wants to use that stored payment method. It no longer has the 3D secure information. And "Editing payment methods at checkout is not supported" by Commerce payment, so we have no way to authenticate with 3D secure at that point. So this all requires some more thought.

lisastreeter’s picture

StatusFileSize
new45.37 KB
new26.54 KB

This patch still needs more work, but it provides a fix for logged-in non-guest checkout. I've only tested "success" scenarios, so if anybody has time to run through test data for both 3ds and normal transactions, that would be helpful https://developers.braintreepayments.com/guides/3d-secure/testing-go-liv...

Also, there's a test failure that needs to be investigated/fixed.

The major change in this patch is the addition of a custom checkout pane for the review step. If a stored payment method is being used and 3ds is enabled, then the 3ds authentication modal will launch so that the payment method can be re-authenticated for 3ds (and that authentication data will show up in the merchant control panel.)

Also, whenever a new 3ds-authenticated payment method is created during a non-guest checkout, that payment method is not stored remotely (in the "vault") until after the payment transaction is processed. Non-3ds stored payment methods are still saved to the vault when the payment method is created. I'm not sure whether it's desirable to change this behavior so that we're doing the same thing in both cases. If so, that will mean a rework of the logic in createPaymentMethod() and createPayment().

lisastreeter’s picture

StatusFileSize
new47.85 KB
new22.23 KB

All tests are passing (locally) for this updated patch, and I've testing through the UI for various combinations of 3DS/non-3DS/PayPal/PayPal credit/authenticated/guest. The 3D-secure authentication information is getting reported as it should in the Braintress sandbox.

I caught and fixed a couple minor logic bugs in the previous patch, and I've tried to clean up the code to make it more readable.

lisastreeter’s picture

Status: Needs work » Needs review

The last submitted patch, 45: braintree_3ds2-3012225-45.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

lisastreeter’s picture

StatusFileSize
new7.02 KB
new48.74 KB

Updated patch fixes some code styling issues but has no changes to functionality.

lisastreeter’s picture

Issue summary: View changes
mglaman’s picture

  1. +++ b/commerce_braintree.install
    @@ -21,3 +21,18 @@ function commerce_braintree_requirements($phase) {
    +    $configuration = $gateway->getPlugin()->getConfiguration();
    +    $configuration['3d_secure'] = '';
    +    $gateway->getPlugin()->setConfiguration($configuration);
    +    $gateway->save();
    

    I know we had this as an opt-in feature before, but should it be? Based on my work with the Stripe support for 3DS 2.0 and SCA, it jus _is_. There is no way to opt-in.

    Has Braintree changed the way 3DS 2.0 works in regards to SCA?

  2. +++ b/css/commerce_braintree.form.css
    @@ -35,6 +40,10 @@
    +#amount {
    +  width: 12em;
    +}
    

    It feels wrong to have a single element with an ID of amount that isn't namedspaced to the module.

  3. +++ b/js/commerce_braintree.review.js
    @@ -0,0 +1,167 @@
    +      braintree.threeDSecure.create({
    +        // Use 3DS 2 when possible.
    +        version: 2,
    +        client: clientInstance,
    +      }, function (threeDSecureErr, threeDSecureInstance) {
    

    Per my earlier comment, this doesn't seem blocked off by the setting.

    EDIT: this is the review.js, which assumes we're using 3DS. sorry.

  4. +++ b/js/commerce_braintree.review.js
    @@ -0,0 +1,167 @@
    +        if (threeDSecureErr) {
    +          console.error(threeDSecureErr);
    +          return;
    +        }
    

    This should be raised somehow. I imagine the error is 3DS auth failure and we need to redirect them somewhere?

  5. +++ b/js/commerce_braintree.review.js
    @@ -0,0 +1,167 @@
    +            $form.trigger('submit', { 'tokenized' : true });
    

    We can't use the form trigger of submit here w/ Commerce 2.14 without the trick of passing data of the triggering element.

    See #3069640: Profile reuse breaks adding payment method via user page.

  6. +++ b/js/commerce_braintree.review.js
    @@ -0,0 +1,167 @@
    +  // This function is copied in whole from hosted-fields-3ds.js.
    +  // Some error cases are likely superfluous here.
    +  Drupal.commerceBraintreeAuthorization.prototype.errorMsg = function (tokenizeError) {
    

    Should we add a helper class object?

  7. +++ b/src/Plugin/Commerce/CheckoutPane/Braintree3DSReview.php
    @@ -0,0 +1,269 @@
    +    if (!($gateway->entity->getPlugin() instanceof HostedFieldsInterface)) {
    ...
    +    $configuration = $gateway->entity->getPlugin()->configuration;
    

    In stripe we had to make sure $gateway->entity is not empty.

Drive by review. Have to run. I'll try to add tests as I did for Stripe.

lisastreeter’s picture

+++ b/commerce_braintree.install
@@ -21,3 +21,18 @@ function commerce_braintree_requirements($phase) {
+ $configuration = $gateway->getPlugin()->getConfiguration();
+ $configuration['3d_secure'] = '';
+ $gateway->getPlugin()->setConfiguration($configuration);
+ $gateway->save();
I know we had this as an opt-in feature before, but should it be? Based on my work with the Stripe support for 3DS 2.0 and SCA, it jus _is_. There is no way to opt-in.

Has Braintree changed the way 3DS 2.0 works in regards to SCA?

Unless somebody knows for sure, I'll dig into the documentation on this. When we initially set up 3DS for a client who already had non-3DS Braintree running in production, everything started failing when we switched on the 3DS. It turned out that the cause was that Braintree required them to use an entirely separate merchant account from the one they had been using. They went through some special process to set up a merchant account that would be compatible with 3DS. The existing merchant account could not be used with 3DS. There was no way for the client to just "turn on" their existing merchant account for 3DS. So if this is still the way things work, I don't know if we'd want to force the 3DS on existing non-3DS merchant accounts? I suppose we could just say, "don't update to this latest version until you've created a 3DS merchant account." Or maybe Braintree has integrated 3DS more seamlessly now. Definitely worth looking into, though, to see if we can/should get rid of the setting for 3DS as an opt-in feature.

lisastreeter’s picture

+++ b/css/commerce_braintree.form.css
@@ -35,6 +40,10 @@
+#amount {
+ width: 12em;
+}
It feels wrong to have a single element with an ID of amount that isn't namedspaced to the module.

Looks like there are several non-namespaced elements in commerce_braintree.form.css: expiration-month, expiration-year, cvv, and amount. Should we "fix" all of them? Do we need to leave the existing ones as is for BC?

UPDATE: actually, this #element isn't even being used, so it should be removed entirely.

lisastreeter’s picture

I think we need to keep 3DS as an opt-in feature based on the current documentation provided by Braintree.

1. Braintree accounts need to be specifically verified (for either 3DS 1 or 3DS 2). It's not automatic that an account is "enrolled" in 3DS 2. See: https://articles.braintreepayments.com/guides/fraud-tools/3d-secure.

2. Elsewhere in the documentation, it states that there, "may be additional per transaction fee to process 3D Secure transactions". So we may want to allow merchants to opt-out, if they're operating in an environment in which SCA is not a concern and they want to avoid the additional fees?

Generally, it seems like Braintree is still saying that moving to 3DS is something merchants might want to do, if they transact in the EU. It doesn't look like they've fully transitioned everything to 3DS being just "the standard".

mglaman’s picture

If Braintree hasn't done a full migration to SCA/3DS by default, then I think we can probably merge this patch, pending CSS notes in #53

lisastreeter’s picture

StatusFileSize
new4.12 KB
new49.73 KB

New patch fixes CSS issues described in #53, provides fix for Commerce issue #3069640: Profile reuse breaks adding payment method via user page, replaces console.error() statement with user-facing error message on the form, and ensures $gateway->entity is not empty (see #51).

mglaman’s picture

Started from the bottom. Noticed a few things.

  1. +++ b/src/Plugin/Commerce/PaymentGateway/HostedFields.php
    @@ -289,7 +403,25 @@ class HostedFields extends OnsitePaymentGatewayBase implements HostedFieldsInter
    +    if (\Drupal::currentUser()->isAnonymous() || !empty($payment_details['payment_method_3ds'])) {
    

    Should we inject the current user? or rather we should be checking the owner of the payment method. The owner of the payment method should be reflective of the current user.

  2. +++ b/src/PluginForm/HostedFields/PaymentMethodAddForm.php
    @@ -61,8 +113,28 @@ class PaymentMethodAddForm extends BasePaymentMethodAddForm {
    +    if (!empty($configuration['3d_secure']) && $order = $this->routeMatch->getParameter('commerce_order')) {
    +      // @todo should this be rounded?
    +      $amount = $order->getBalance()->getNumber();
    +    }
    

    It probably needs to be moved to minor units. Let's do so, to be safe, and remove the @todo.

  3. +++ b/src/PluginForm/HostedFields/PaymentMethodAddForm.php
    @@ -61,8 +113,28 @@ class PaymentMethodAddForm extends BasePaymentMethodAddForm {
    +    if ($amount > 0) {
    +      // Amount is valid, so we can use hosted fields with 3DS.
    +      $element['#attached']['library'][] = 'commerce_braintree/hosted-fields-3ds';
    +    }
    +    elseif ($configuration['3d_secure'] == 'required') {
    +      // We need the amount for 3DS but do not have it.
    +      throw new PaymentGatewayException('Unable to find order entity for the payment method.');
    +    }
    

    It looks like this is forcing 3DS on the payment add form no matter the configuration, so long as we have a known amount.

lisastreeter’s picture

#57-1

Should we inject the current user? or rather we should be checking the owner of the payment method. The owner of the payment method should be reflective of the current user.

Yes, let's check the owner of the payment method. I think logic will be easier to read here if I flip the order of the if/else conditions and have this instead:

if ($owner && $owner->isAuthenticated() && empty($payment_details['payment_method_3ds']))

#57-2 -- yes, good catch. Changing this.

#57-3 Actually, "amount" is only set for 3Ds, so the logic works here. Should I add a comment to make this more clear or change the conditions so that it's more obvious? We have now:

    // Need the payment amount for 3D Secure verification.
    $amount = 0;
    if (!empty($configuration['3d_secure']) && $order = $this->routeMatch->getParameter('commerce_order')) {
      $amount = $this->toMinorUnits($order->getBalance());
    }

    if ($amount > 0) {

Could change to getting the amount in either case and then checking the condition after:

    // Need the payment amount for 3D Secure verification.
    $amount = 0;
    if ($order = $this->routeMatch->getParameter('commerce_order')) {
      $amount = $this->toMinorUnits($order->getBalance());
    }

    if (!empty($configuration['3d_secure']) && $amount > 0) {
mglaman’s picture

Maybe we should only fetch and round the amount if we're using 3DS instead of it being a qualifier for 3DS being activated.

+        'enabled' => $this->t('Enabled'),
+        'required' => $this->t('Required'),

If not empty, get the amount. If the amount is not found and `required` throw an error.

lisastreeter’s picture

StatusFileSize
new51.88 KB
new5.17 KB

Thanks, Matt. That logic update makes sense. I think this patch covers all the review comments.

Using $this->toMinorUnits() was problematic because it's a protected gateway plugin method. I ended up just copying-and-pasting the entire method into PaymentMethodAddForm. Perhaps we should open a Commerce core issue to make it a public method so that it can be used in places other than gateway plugins?

mglaman’s picture

Using $this->toMinorUnits() was problematic because it's a protected gateway plugin method. I ended up just copying-and-pasting the entire method into PaymentMethodAddForm. Perhaps we should open a Commerce core issue to make it a public method so that it can be used in places other than gateway plugins?

There is an issue, its been open for a bit. I've just copied the logic over as well.

thronedigital’s picture

Is this being tested against recurring?

mglaman’s picture

@thronedigital no, Stripe was not either. The main goal is to focus on on-session purchase flows and then handle recurring.

lisastreeter’s picture

Status: Needs review » Needs work
StatusFileSize
new51.19 KB
new3.11 KB

After the latest Commerce release, toMinorUnits() is now a public method for payment gateway plugins. I updated the patch to use this method in the payment method add form.

Then while re-testing on my local dev, I discovered a bug related to the interaction between the billing address selection form and the javascript for the hosted fields js. These two lines were added to fix a bug related to payment methods created manually through the UI:

$form.append('<input type="hidden" name="_triggering_element_name" value="' + $submit.attr('name') + '" />');
$form.append('<input type="hidden" name="_triggering_element_value" value="' + $submit.val() + '" />');

But if the customer attempts to change the billing address during checkout, the payment form breaks. So I applied the same change as in https://www.drupal.org/project/commerce_braintree/issues/3077453, which fixed the bug.

However, the user payment method add form still does not work for 3DS, because 3DS authentication requires the payment amount, which it gets during checkout from the order. The user payment method add form does not have an order, and we no longer fall back to non-3DS version when the order is missing. We could rework the logic to allow users to create non-3DS stored credit cards, but that's probably not what we want. Perhaps it would be better to create with a small, fixed amount? The stored 3DS method would then get re-authenticated whenever the payment method actually gets used.

p.lavelle’s picture

Hi,

May I ask if there has been any futher progress on this?

martijn de wit’s picture

StatusFileSize
new52.45 KB

port #64 to a working version for dev 0ddc6fb

@todo apply same check as #3090170: Add subsource integrety for external JS

martijn de wit’s picture

StatusFileSize
new52.62 KB

Added a hash as every file has one now per #3090170: Add subsource integrety for external JS.

martijn de wit’s picture

StatusFileSize
new51.74 KB

Fixed some typos. Prettifier used singel quotes :|

sittard’s picture

We have just upgraded to Drupal Commerce 2.18 and I'm trying to apply patch #68 against the latest commerce_braintree dev a49099d. Patch seems to apply but when we get to the checkout page /checkout/123/order_information I'm getting the following error:

Drupal\Core\Asset\Exception\InvalidLibraryFileException: Invalid library definition in modules/contrib/commerce_braintree/commerce_braintree.libraries.yml: yaml_parse(): parsing error encountered during parsing: did not find expected key (line 60, column 4), context while parsing a block mapping (line 47, column 3) in Drupal\Core\Asset\LibraryDiscoveryParser->parseLibraryInfo() (line 322 of core/lib/Drupal/Core/Asset/LibraryDiscoveryParser.php).

The braintree checkout appears to work OK without the patch installed. Also tried to install #47 against the latest dev and this won't install for me either. Any ideas?

Thanks.

sittard’s picture

It would appear that commerce_braintree.libraries.yml file has an extra indentation around line 60 (dependencies) should be:

braintree-3d-secure:
  remote: https://github.com/braintree/braintree-web
  version: "3.51.0"
  license:
    name: MIT
    url: https://github.com/braintree/braintree-web/blob/3.51.0/LICENSE
    gpl-compatible: true
  js:
    https://js.braintreegateway.com/web/3.51.0/js/three-d-secure.min.js:
      minified: true
      type: external
      attributes:
        integrity: "sha384-XdodPgvSHvNVdXatHHLHbM5L4ADyIzbNLqv+2rynYLHiXu9OxW6f/uCnjJ8H3Lgm"
        crossorigin: anonymous
  dependencies:
    - commerce_braintree/braintree
sittard’s picture

StatusFileSize
new51.69 KB

Fixed indentation issue in commerce_braintree.libraries.yml

sittard’s picture

StatusFileSize
new52.88 KB

The previous patch was failing in Google Chrome due to invalid subsource integrety for external JS files - https://www.drupal.org/project/commerce_braintree/issues/3090170

I've updated the patch with new SRI hashes using https://www.srihash.org/

sittard’s picture

During testing we noticed that the value being sent to 3DS has a rounding error so instead £55.60 the 3DS modal was displaying £5560.00.

The source of the problem seems to be:

// Need the payment amount for 3D Secure verification.
    $amount = 0;
    if (!empty($configuration['3d_secure'])) {
      if ($order = $this->routeMatch->getParameter('commerce_order')) {
        $amount = $plugin->toMinorUnits($order->getBalance());
      }

Which we changed back to:

 // Need the payment amount for 3D Secure verification.
    $amount = 0;
    if (!empty($configuration['3d_secure']) && $order = $this->routeMatch->getParameter('commerce_order')) {
      // @todo should this be rounded?
      $amount = $order->getBalance()->getNumber();
    }

I've not attached a patch as I'm not 100% certain this is the best way forward.

But hopefully that bit of testing helps. Apart from that I think this is now production ready.

luksak’s picture

Hm, Braintree is putting some pressure on us:

To help you prepare for upcoming SCA requirements, part of the European Payment Services Directive (PSD2) regulations, Braintree recommends that merchants integrate 3DS 2 into their checkout experience by December 2020 to ensure there is no disruption to you or your customers at checkout.

Is there funding from Braintree to fix this?

lisastreeter’s picture

@sittard I was just reading through the documentation for the "amount" passed as one of the verifyCard options. It should be...

The amount of the transaction in the current merchant account's currency. This must be expressed in numbers with an optional decimal (using .) and precision up to the hundredths place. For example, if you're processing a transaction for 1.234,56 € then amount should be 1234.56.

So I agree that it makes sense to not use toMinorUnits(). The only issue is that some currency use precision up to the thousandth's place, so I think we need to do something like:

$amount = Calculator::round($order->getBalance()->getNumber(), 2);

So I'm going to make that change, re-roll the patch, and see how that works.

It's been a while since I worked on this issue, so I went through all the comments to try to identify all the to-dos.

1. It seems that adding email address and telephone numbers to verifyCard for 3DS2 is still an issue.
2. Comment #33 describes the need to implement "Amex safe key", but I haven't seen any newer reports of Amex issues.
3. Comment #64 describes an issue related to the User payment method add form not working (because there's no order).

So I'll go through and look at these specifically. Anything else that's missing?

sittard’s picture

Thanks for picking this up. We have been using patch #72 on a production server for a while, the only issue we've found is for orders which have a shipping calculation (majority don't). In these case the shipping was not being added to the 3D secure popup, but was being added to the final payment resulting in a payment error message being displayed.

Partly this is because we have the payment and shipping information on the order information pane in our checkout workflow. However, as noted in the post below a workaround would be to have the shipping on the Review Pane.
https://www.drupal.org/project/commerce_shipping/issues/2849756#comment-...

This issue should probably be dealt with in commerce shipping and I guess goes beyond what is required here.

lisastreeter’s picture

StatusFileSize
new50.71 KB

@sittard - thanks for the feedback! I'll add that to the list of things to check.

Patch #72 didn't apply with the latest dev version (conflicts in libraries.yml and paypal.js). So I've rerolled. New patch just fixes those conflicts and does not contain anything new.

lisastreeter’s picture

StatusFileSize
new3.5 KB
new51.08 KB

This update addresses a couple of the issues outlined in #75 and #76.

First, I'm not having any issues with AmEx transactions. Everything goes through to the sandbox just like other credit cards. If US merchants want Amex Safe Key, I think that can be a follow-up issue.

Second, there are a couple issues related to the "amount" that gets passed to verifyCard for the initial verification. We have been using toMinorUnits() to calculate the amount, but that's not what Braintree wants. Per Braintree documentation, the value should be the same as the charge amount (order balance), rounded to two decimal digits. If the verifyCard amount is greater than the amount to be charged, that is problematic since the value displays to the customer on the 3DS modal. If the amount is less than the total order amount, the modal will work but then checkout will fail at the final confirmation due to the amount mismatch.

So I've replaced the order balance calculation that resulted in incorrect values displaying on the 3DS modal:

$amount = $plugin->toMinorUnits($order->getBalance());

Instead, I use the Calculator service to round the units to 2 decimal places (per Braintree documentation).

The second part of the problem related to the amount relates to having Commerce Shipping enabled or any other functionality that allows customers to update the order amount on the same checkout step as the 3D Secure modal launch (i.e., the Payment Information pane). One workaround is modifying checkout flow so that Shipping method selection is on a separate, earlier step. A better solution would be beyond the scope of this issue, since we can't anticipate all the ways checkout could be configured to allow customers to make changes to the order amount prior to the review step.

What I've done in this patch is add a hidden "order balance" form element on the Payment information checkout pane. The 3d secure javascript grabs the balance amount right before launching the modal, so other contrib/custom modules like Shipping could update the value via javascript.

lisastreeter’s picture

StatusFileSize
new50.65 KB
new5.69 KB
new3.72 KB

In this update, I've investigated the data requirements for the verifyCard call. For 3DS 2, the only required values are amount, vin, nonce. Email, billingAddress, and additionalInformation should be included if possible.

I've added in email, using the order email value when available. (For guest checkout, the email may not be set yet.) We were already passing in the billing address, though without phone number(s), since they aren't a standard part of billing profiles. However, I've determined that the code for billing address data is no longer functional, due to updates in commerce core related to address book. Also, if commerce shipping is installed, getting the correct address data is further complicated by the "billing same as shipping" option. So... what I've done in this patch is completely remove the billing address data from the verifyCard. Yes, it would be nice to have that in there, but it's just too complicated to tackle for this issue.

To summarize, this patch adds in email when available and removes the billing address data from the verifyCard call.

Still to-do is fixing the user payment method add form for 3D secure.

lisastreeter’s picture

StatusFileSize
new5.69 KB
new3.72 KB

Oops, attached those interdiff files with .patch extensions. Uploading with .txt now.

lisastreeter’s picture

Status: Needs work » Needs review
StatusFileSize
new51.31 KB
new7.85 KB
new3.11 KB

Updated patch supports the user payment method add form.

luksak’s picture

Ok, so the deadline on December 31st is coming closer. I'll be testing this the coming days.

Are there specific things I should be testing?

How can I test this in the sandbox?

sittard’s picture

Sandbox - I think you need to contact braintree to get a sandbox account
https://sandbox.braintreegateway.com

Braintree Test Card Details
https://developers.braintreepayments.com/guides/credit-cards/testing-go-...

3D Secure 2.0 Test Card Details
https://developers.braintreepayments.com/guides/3d-secure/testing-go-liv...

luksak’s picture

Status: Needs review » Needs work

A first report of my testing:

In sandbox mode 3DS 2.0 works. When testing in production mode I got this error:

InvalidArgumentException: $payment_details must contain the payment_method_nonce key. in Drupal\commerce_braintree\Plugin\Commerce\PaymentGateway\HostedFields->createPaymentMethod() (line 402 of modules/contrib/commerce_braintree/src/Plugin/Commerce/PaymentGateway/HostedFields.php).

lisastreeter’s picture

@Lukas, it's possible that your merchant account was not set up for 3d-secure. We had a client that talked to Braintree about activating their account for 3DS. After testing everything thoroughly on the dev site, we activated 3DS on production and started getting that same error message you're seeing. After hours spent trying to diagnose the problem and requesting support from Braintree, we learned that 3DS functionality was never added to their existing merchant account. Instead, an entirely new merchant account had been created for them, for 3DS.

I'm not sure if Braintree still requires merchants to explicitly request 3DS functionality, but it might be worth trying to verify with Braintree that your production account is actually 3DS-enabled.

luksak’s picture

StatusFileSize
new828 bytes

I realized that there was a incorrect indent in commerce_braintree.libraries.yml causing the url for three-d-secure.min.js being incorrect. The attached patch fixes that issue.

luksak’s picture

StatusFileSize
new50.83 KB

Sorry, the patch went missing...

luksak’s picture

@lisastreeter Sorry, somehow I had this issue open for days without refreshing. Just saw your comment. According to Braintree support, 3DS is always enabled.

The patch in #87 solved the issue for me. I just processed a 3DS 2.0 payment on production.

The only thing which isn't working is PayPal. The popup opens (after clicking the PayPal button, but that is a different issue) and I can add my PayPal account. When proceeding in the checkout, I get the following error:

    Notice: Undefined index: card_type in Drupal\commerce_braintree\Plugin\Commerce\PaymentGateway\HostedFields->createPaymentMethod() (line 448 of modules/contrib/commerce_braintree/src/Plugin/Commerce/PaymentGateway/HostedFields.php).
    We encountered an error processing your payment method. Please verify your details and try again.

In the logs it says:

Unsupported credit card type "".

lisastreeter’s picture

StatusFileSize
new51.73 KB
new2.32 KB

@lukas-von-blarer Thanks for the bug report! I was able to reproduce when checking out as a Guest. This new patch should fix.

Any additional testing/feedback would be very helpful!

lisastreeter’s picture

Status: Needs work » Needs review

(forgot to update status)

luksak’s picture

The patch fixes the issue with PayPal. Thank you so much!

The error I described in #88 doesn't occur either.

What i missing to get this committed? Do we need tests?

jsacksick’s picture

I've been testing this manually today and realized there are several "issues", not necessarily with the patch itself though.

The patch can only work properly if the payment method is collected right before creating the payment transaction (i.e on the review page).

The main reason for that is that the order total might not be "final" when we create the payment method nonce, if the payment information pane is on the order information step for example.

Alas, we're forced to pass an amount to authorize from the 3DS JS (i.e the call to verifyCard()), and if the amount then differs when creating the transaction, it'll fail.

It can work if the amount is slightly higher (I believe there's a 15% tolerance), or lower, but if more items are added to the cart after the payment method nonce is created, or simply if shipping/taxes are inflecting the order total too much, capturing/authorizing the payment will fail.

So unfortunately once again, the only way for this to work properly would be to put the payment information pane on the review page, sad, but true...

I'm wondering if we should commit the patch as it is... And basically add a note to the project page / documentation saying the payment information pane must be on the review page in order for the 3DS2 implementation to work properly.

@ Lukas von Blarer, @lisastreeter: thoughts?

jsacksick’s picture

hm... Would it actually be possible to just tokenize the card like before? And fire the 3DS2 verification on the review page?

jsacksick’s picture

I started making changes to the patch, and basically kept using the regular JS that simply tokenizes the card (instead of the 3DS JS).

That actually creates a reusable payment method, which then makes the 3DS review checkout pane to be visible.

The 3DS modal is then triggered, there's a remaining issue when creating the payment, but this probably simply requires more work...

It seems that it's still possible to tokenize the card first and then worry about 3DS on the review page.

jsacksick’s picture

Status: Needs review » Needs work

Setting back to needs work, I'll try to work on a patch.

jsacksick’s picture

Status: Needs work » Needs review
StatusFileSize
new26.25 KB
new31.14 KB

Ok, I've worked on this, removed a lot of code that was introduced (removed the hosted-fields-3ds.js and only do the 3dsecure on review while still doing the regular tokenization... when adding the payment method.

I probably killed the user pages integration (was focused on making the "regular" usecase work"), and I probably removed too much of the introduced code (i.e no more doCreate3dsPayment() method...

But surprisingly, this seems to work, and I got rid of the errors I've experienced myself when making changes to the order after tokenizing the card with 3DS in checkout...

@lisastreeter, @ Lukas von Blarer: Curious to see how testing goes for you guys...

We may need to put back some of the code I've cleaned (testing a very specific usecase), but at least I didn't get issues when trying to create a transaction with a higher amount that was was authorized in the 3DS modal.

jsacksick’s picture

StatusFileSize
new24.24 KB
new24.24 KB

Attaching a patch with minor changes (Removed the button selector setting on the pane). Since we have access to the form, we can pass the form ID directly.

Also made minor cosmetic changes here and there...

jsacksick’s picture

StatusFileSize
new10.64 KB

Attached 2 times the same patch instead of an interdiff.

jsacksick’s picture

StatusFileSize
new24.1 KB
new1.87 KB
sumi’s picture

Status: Needs review » Reviewed & tested by the community

Tested the latest patch and it is working as expected.

  • jsacksick committed 2c7c85d on 8.x-1.x
    Issue #3012225 by lisastreeter, jsacksick, sittard, Martijn de Wit,...
jsacksick’s picture

Status: Reviewed & tested by the community » Fixed

Committed!!! Thanks everyone! This was long overdue :).

luksak’s picture

Status: Fixed » Needs review

Thank you!

I already released the patch in #89 and I cant test the committed patch right now.

We still have this issue on 7.x: #2496627: Support 3D Secure In case you could have a look at the patch, that'd be great!

jsacksick’s picture

Status: Needs review » Fixed

Hm, it doesn't really make sense to update this issue "needs review", the patch got committed and a new release was tagged (so there's nothing to review anymore).

From https://www.drupal.org/docs/develop/issues/fields-and-other-parts-of-an-...

Needs review ["CNR"] (#)
A patch has been created and needs review and testing. The Testing Bot uses this status to trigger an automated review of the patch and reports the results. Patch reviewers also use this status to find patches that need to be reviewed and evaluated. With sufficient positive feedback, the patch may be promoted to the status "Reviewed & tested by the community" [see next definition]. If a reviewer, either human or Bot, finds a problem with the patch, it will then be marked as "Needs work". Note that if a patch is not required in order to complete the idea described in the issue, then it is the idea itself that needs review.

Feel free to open a new issue if you need to report a bug, but this is now in, and had to be committed prior to the January 1st deadline.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

rob230’s picture

Can anyone explain how this is supposed to work? It doesn't seem to do anything. On the payment step three-d-secure.min.js is not added, and it just does a normal payment and processes it. The three-d-secure.min.js script is added to the review step after the payment has been taken and the order is complete. At no point does it ever ask for any additional authentication from the bank.

I've tried with the fail cards from the documentation and it still succeeds. I don't really understand how it's supposed to work.

skitten’s picture

I'm also having issues with this. Live transactions failing (authentication required 2099), but I can't figure out how to test against the Braintree sandbox.

martijn de wit’s picture

@Rob230 and Skitten, Best way to get support is to open a new ticket with the category "support".

A closed ticket doesn't pop-up in all dashboard views.

ahir’s picture

Hi

Not working for logged in user witg D9

Error:

Error: Call to a member function getParameter() on null in Drupal\commerce_braintree\PluginForm\HostedFields\PaymentMethodAddForm->buildCreditCardForm() (line 81 of /httpdocs/web/modules/contrib/commerce_braintree/src/PluginForm/HostedFields/PaymentMethodAddForm.php)

here is the code:

if (!empty($configuration['3d_secure'])) {
if ($order = $this->routeMatch->getParameter('commerce_order')) {
$amount = $order->getBalance()->getNumber();
}