Problem/Motivation
The Authorize.net module has the most strict PCI compliance requirements. We can improve this to SAQ-A-EP by implementing Accept.js. The Accept.js implementation allows you to embed input fields which are then submitted to the Authorize.net servers directly via JavaScript and return a nonce payment token. This is similar to how Braintree, Stripe, and Square payment gateways work.
Using Accept.js and nonce based payment workflow fixes #2892467: Does not support anonymous checkout.
Proposed resolution
Implement Accept.js
Integrating the Accept.js library into your application helps minimize your PCI compliance because it sends payment data directly to Authorize.Net. Payment data submitted through Accept.js does not reach your server. Accept.js also provides the ease of flexibility of your own design and form.
API: https://developer.authorize.net/api/reference/features/acceptjs.html
Remaining tasks
While Accept.js is SAQ A-EP and Braintree/Square/Stripe are SAQ A, the implementation is the same. Each module can be used as a reference point. It's just that the latter modules use div which turn into iframes rather than direct inputs.
- Add the Accept.js JavaScript SDKs as library definitions: Sandbox: https://jstest.authorize.net/v1/Accept.js, Production: https://js.authorize.net/v1/Accept.js
- Override the
add-payment-methodform handler.: Provide a custom form handler which embeds the HTML inputs that will be read and processed by Accept.js. - Implement module JavaScript to interact with form elements and submit to Authorize.net: See the JavaScript example provided: https://developer.authorize.net/api/reference/features/acceptjs.html#Int.... We need to make sure it clears input values so they do not get POST'd
- Change
createTransactionRequestcall to useopaqueDatain payment data: Review http://developer.authorize.net/api/reference/index.html#payment-transact....
User interface changes
The credit card form will change appearance due to class name changes.
API changes
No direct API changes. Only internal method logic changes.
Data model changes
None.
| Comment | File | Size | Author |
|---|---|---|---|
| #33 | interdiff.txt | 809 bytes | smccabe |
| #33 | use_accept_js_to_ease-2813401-33.patch | 28.09 KB | smccabe |
Comments
Comment #2
shootersolutions commentedBased on my understanding, this is a critical issue for Authorize.net standard, where only communication is to be from the Customer to them:
As Authorize.net does not in any way their service to Ever be used where communication goes Anywhere else but from the customer to Authorize.net and then back to the server;
As standard exists to have the credit card data not to go through any in between server, and should be the standard option of an Auth.net module.
Comment #3
jenlamptonI'm also interested in switching to accept.js on a Drupal 7 commerce site. Is there another issue where that's being worked on already, or should I create one?
Comment #4
pjcdawkins commentedHaving a look at this in a sprint...
Comment #5
mglamanpjcdawkins, any update? Tagging for MidCamp sprint.
Comment #6
mglamanBumping priority and documenting path forward.
Comment #7
mglamanComment #8
mglamanComment #9
mglamanComment #10
mglamanUnassigning, done updating summary.
Comment #11
mglamanAdded
OpaqueDataobject to the SDK. https://github.com/commerceguys/authnet/commit/7c351f60b942c9fd08a53e32b...When working on the patch, make sure SDK is checked out to that commit. This will be passed to the
paymentproperty instead of theCreditCardobject.Comment #12
nikathoneStarted some work on this at https://github.com/drupalcommerce/commerce_authnet/pull/2 still need to refactor the js and update the tests. Any feedback are welcome.
Comment #13
mglamanWith this we need to update ludwig.json to target beta2
Comment #14
mglamanPutting nikathone's latest patch here.
Comment #15
czigor commentedFixed the issues raised in the PR review. Changed the SDK lib version in ludwig.json to beta2.
Could you have a look, @nikathone?
Comment #16
chrisrockwell commentedMaybe shouldn't be fixed here, but this is likely to be NULL. See #2918851: invoiceNumber is null
Comment #17
czigor commentedJust removing the already commented
'state' => $address->getAdministrativeArea(),line.Comment #18
subhojit777@czigor I applied the patch #17 but it is giving an error
Comment #19
mglamanBecause we're not defaulting the value anywhere, from quick search.
Why did this change from order->getEmail?
Comment #20
subhojit777I am also getting a warning Unsupported credit card type "XXXX1111". I am using a sandbox authorize.net account. I don't know whether I am missing some setting, or the patch is not working.
Comment #21
subhojit777Okay. So I figured the error in #18. I am using a custom payment pane and that is why it is unable to get the provided email id.
Re: #19 I noticed that
$owneris the current order's user. I am trying to do anonymous checkout, and in that case it is empty.There might be a better way to get the email provided during checkout, that would be independent of the payment pane.
Comment #22
subhojit777Re: #20
I am getting confirmation mails from ADN that the payment has been approved. So it looks like the patch is partially working. Is able to trigger the payment, but somehow the patch is unable to catch the correct reponse and throwing the warning? Maybe.. due the custom payment pane that I am using this is happening.
Comment #23
mglamanPlease test on vanilla 2.x
Comment #24
subhojit777Sorry 2.x version of what? I checked that there is only 1.x of commerce_authnet available.
Comment #25
travis-bradbury commentedVanilla seems fine. It worked fine with the default checkout panes.
Subhojit, the issue appears to be from overriding the payment_information and contact_information panes.
Drupal\commerce_authnet\PluginForm\AuthorizeNet\PaymentMethodAddForm::submitCreditCardForm()uses the IDs of the original panes.Comment #26
nikathoneThe accept.js feature has been recently updated by Authorize.net to include using the javascript with the hosted form. I am wondering if we shouldn't update our js to use this approach instead since the hosted form sample response object:
include some of the fields I was struggling to get when doing the initial patch.
Comment #27
mglamanThose are two different methods: Accept.js and Accept UI. We will be implementing the later as well.
Comment #28
subhojit777As per the patch in #17 if there is any error in the payment, then instead of showing the error it throws more errors like this:
Notice: Undefined index: #parents in Drupal\Core\Form\FormState->getError() (line 1112 of core/lib/Drupal/Core/Form/FormState.php).
I tried adding a
#parentsto the credit card elements but it does not seem to work.Comment #29
subhojit777Comment #30
subhojit777This patch prevents error
Notice: Undefined index: #parents in Drupal\Core\Form\FormState->getError() (line 1112 of core/lib/Drupal/Core/Form/FormState.php).
showing up if any error occurs during payment.
Comment #31
subhojit777High five to Shawn McCabe https://www.drupal.org/u/smccabe for helping me.
Comment #32
mglamanWe need to clear these values on submit. Then I'll merge the patch.
A follow up issue is the fact Accept.js does not validate the card number, or it silently (or something) fails. I need to push forward #2790551: Implement a JS library for the credit card form. And until Commerce 2.2 is released, we can host a version of it in Auth.net to provide credit card validation.
Comment #33
smccabe commentedAdded code to clear values on submit, as well as a little documentation explaining why.
Comment #34
czigor commentedLooks good from here.
Comment #35
mglamanCommitted, thanks everyone! Now for follow ups.
Comment #37
adrian83 commentedThank you, everyone!
Comment #39
vasantha raja commentedOur site is running on Drupal 8.5.4 and the Commerce version of 8.2.6.
The JS library from the authorized.net is loaded into the site. (For sandbox account).
<script src="//jstest.authorize.net/v1/Accept.js" charset="utf-8"></script>But we are seeing the error in the console.
"E_WC_01: Please include Accept.js library from cdn".
Any assist in this will be really appreciated.
Comment #40
hockey2112 commentedSame here: "Please include Accept.js library from cdn." Is it necessary to upload the Accept.js file to my libraries? If so, what is the proper directory structure? This module has no readme file, so this is a bit confusing.
Comment #41
adrian83 commentedNot sure if this is a helpful answer, but here goes: I'm still running rc1, required via my project's composer.json. Here is a path to some accept code: /modules/contrib/commerce_authnet/js/commerce_authnet.accept.form.js. I may be wrong, but seems to me this is the only Accept.js code needed?