How to Implement 3DS2 Authentication in Adyen Salesforce Commerce Cloud
To implement 3DS2 authentication in the Adyen SFRA integration, ensure the cartridge invokes AdyenHelper.add3DS2Data() to inject the authenticationData block into payment requests, handle non-final CHALLENGESHOPPER responses in the authorize middleware, and render the challenge using the Adyen Web SDK's handleAction() method with the threeDSIframe element.
The adyen/adyen-salesforce-commerce-cloud repository provides native 3DS2 (Three-Domain Secure 2.0) support through built-in helpers and middleware. Understanding how to implement 3DS2 authentication requires knowledge of the server-side request preparation, the Adyen Checkout API response handling, and the client-side iframe rendering flow. This guide walks through the exact file paths and function calls required to enable secure, frictionless card authentication in your SFRA storefront.
How 3DS2 Authentication Works in the SFRA Cartridge
The 3DS2 implementation follows a three-phase architecture that is already wired into the cartridge:
- Server-side request preparation – The integration adds an
authenticationDatablock to the Checkout request, telling Adyen to use the native 3DS2 flow and supplying the shopper's origin. - Adyen response handling – The Checkout API returns a non-final result code such as
CHALLENGESHOPPERorIDENTIFYSHOPPER. The response contains an action object that the frontend must execute. - Client-side UI rendering – The SFRA checkout page uses the Adyen Web SDK (
Checkoutcomponent) to render the 3DS2 challenge in an iframe (iframe[name='threeDSIframe']). The shopper completes the challenge, the SDK returns the result to the server, and the transaction finalizes.
Server-Side Configuration for 3DS2
Adding Authentication Data to Checkout Requests
The core helper function add3DS2Data in src/cartridges/int_adyen_SFRA/cartridge/adyen/utils/adyenHelper.js constructs the required authentication payload. This function is invoked automatically when creating payment requests.
// adyenHelper.js – add3DS2Data (lines 620-627)
add3DS2Data(jsonObject) {
jsonObject.authenticationData = {
threeDSRequestData: {
nativeThreeDS: 'preferred',
},
};
jsonObject.channel = 'web';
const origin = `${request.getHttpProtocol()}://${request.getHttpHost()}`;
jsonObject.origin = origin;
return jsonObject;
}
The createPaymentRequest flow in src/cartridges/int_adyen_SFRA/cartridge/adyen/scripts/payments/adyenCheckout.js calls this helper at line 156:
// adyenCheckout.js – part of createPaymentRequest
let paymentRequest = AdyenHelper.createAdyenRequestObject(
orderNumber,
orderToken,
paymentInstrument,
order.getCustomerEmail(),
);
AdyenHelper.setPaymentInstrumentFields(paymentInstrument, paymentRequest);
paymentRequest = AdyenHelper.add3DS2Data(paymentRequest); // 3DS2 injected here
Enabling 3DS2 for Zero-Auth Tokenization
For saved card tokenization (zero-amount authorizations), the same helper ensures 3DS2 compliance. In src/cartridges/int_adyen_SFRA/cartridge/adyen/scripts/payments/adyenZeroAuth.js at line 37:
// adyenZeroAuth.js – zero-auth request preparation
zeroAuthRequest = AdyenHelper.add3DS2Data(zeroAuthRequest);
This ensures that stored payment methods also trigger the 3DS2 flow when required by the issuing bank.
Handling Non-Final Responses in the Authorize Middleware
The authorize middleware interprets Adyen's response and determines whether additional authentication is required. Located in src/cartridges/int_adyen_SFRA/cartridge/adyen/scripts/hooks/payment/processor/middlewares/authorize.js (lines 52-57), the logic checks the isFinal property:
// authorize.js – simplified flow
const result = adyenCheckout.createPaymentRequest({ Order: order, ... });
if (result.error) return errorHandler();
const checkoutResponse = AdyenHelper.createAdyenCheckoutResponse(result);
if (!checkoutResponse.isFinal) {
// Result contains an action (e.g., 3DS2 challenge)
return checkoutResponse; // Sent back to the controller / client
}
When Adyen returns result codes CHALLENGESHOPPER or IDENTIFYSHOPPER, the middleware forwards the action object to the frontend. The unit test in src/cartridges/int_adyen_SFRA/cartridge/adyen/scripts/hooks/payment/processor/middlewares/__tests__/authorize.test.js (lines 57-71) validates this behavior by mocking a response containing threeDS2 and asserting the snapshot.
Client-Side Implementation
Rendering the 3DS2 Challenge with the Web SDK
The SFRA checkout page loads the Adyen Web SDK (checkout.js). When the server response contains an action, the SDK renders the challenge inside an iframe named threeDSIframe. Pass the action object to the SDK instance:
// checkout client script (SFRA)
if (serverResponse.action) {
// `checkout` is the Adyen Checkout instance
checkout.handleAction(serverResponse.action);
}
The SDK manages the iframe injection and communication with the 3DS2 ACS (Access Control Server) automatically.
Automated Testing with Playwright
The end-to-end test suite includes a helper to interact with the 3DS2 challenge. In tests/playwright/pages/PaymentMethodsPage.mjs (lines 20-26), the do3Ds2Verification method locates the iframe:
// PaymentMethodsPage.mjs – helper used by the E2E suite
do3Ds2Verification = async () => {
const verificationIframe = this.page.frameLocator(
"iframe[name='threeDSIframe']",
);
await verificationIframe.locator('input[name="answer"]').fill('password');
await verificationIframe.locator('button[type="submit"]').click();
};
Running npm test executes these Playwright tests to verify the complete 3DS2 flow.
Step-by-Step Implementation Checklist
- Install the cartridge – Ensure
int_adyen_SFRAis added to your SFRA site-import and listed inmetadata/site_import/services.xml. - Enable Native 3DS2 – In the Adyen Customer Area, configure the Checkout integration to use "Native 3DS2". No additional toggle is required in the cartridge code.
- Verify helper invocation – Confirm that
AdyenHelper.add3DS2Data()is called inadyenCheckout.js(line 156) andadyenZeroAuth.js(line 37). Only modify if you have overridden the default request creation. - Handle action responses – Ensure the
authorize.jsmiddleware returns non-final responses to the controller. The default implementation already handles this. - Implement frontend action handling – Verify your checkout controller passes the
actionobject from the server response to the Web SDK'shandleAction()method. - Test the flow – Use the Playwright test suite or manual testing with 3DS2 test cards to confirm the
threeDSIframerenders correctly and completes authentication.
Summary
- Server-side: The
add3DS2Datahelper inadyenHelper.jsinjectsauthenticationDatawithnativeThreeDS: 'preferred'into all payment requests. - Middleware: The
authorize.jsmiddleware detects non-final result codes (CHALLENGESHOPPER/IDENTIFYSHOPPER) and returns the action object to the client. - Client-side: The Adyen Web SDK renders the challenge in an iframe named
threeDSIframewhenhandleAction()receives the server response. - Testing: Playwright tests in
PaymentMethodsPage.mjsverify the iframe interaction usingframeLocator("iframe[name='threeDSIframe']"). - Tokenization: Zero-auth flows automatically include 3DS2 data via the same helper used in standard payments.
Frequently Asked Questions
Does the cartridge require manual configuration to enable 3DS2?
No. The add3DS2Data helper is invoked by default in both adyenCheckout.js and adyenZeroAuth.js. You only need to ensure your Adyen account has Native 3DS2 enabled in the Customer Area. If you have overridden the payment request creation logic, manually call AdyenHelper.add3DS2Data(paymentRequest).
What result codes indicate a 3DS2 challenge is required?
Adyen returns CHALLENGESHOPPER for the challenge flow or IDENTIFYSHOPPER for the frictionless flow. The authorize.js middleware checks checkoutResponse.isFinal to detect these non-final states and forwards the action object to the frontend for rendering.
How does the integration handle 3DS2 for stored payment methods?
The adyenZeroAuth.js script (line 37) calls add3DS2Data when tokenizing cards for future use. This ensures that saved cards trigger 3DS2 authentication during the zero-amount authorization, complying with PSD2 Strong Customer Authentication requirements for stored credentials.
Can I customize the logic after the 3DS2 challenge completes?
Yes. After the Web SDK submits the challenge result and the authorization hook receives a final response, you can implement custom business logic in the hook entry points located in src/cartridges/int_adyen_SFRA/cartridge/scripts/helpers/hooks. These hooks execute after the middleware returns a final result, allowing you to modify order status or trigger additional integrations.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →