# How to Implement 3DS2 Authentication in Adyen Salesforce Commerce Cloud

> Learn how to implement 3DS2 authentication in Adyen Salesforce Commerce Cloud. This guide covers injecting authentication data and handling challenges for secure payments.

- Repository: [Adyen/adyen-salesforce-commerce-cloud](https://github.com/adyen/adyen-salesforce-commerce-cloud)
- Tags: how-to-guide
- Published: 2026-02-23

---

**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:

1. **Server-side request preparation** – The integration adds an `authenticationData` block to the Checkout request, telling Adyen to use the native 3DS2 flow and supplying the shopper's origin.
2. **Adyen response handling** – The Checkout API returns a **non-final** result code such as `CHALLENGESHOPPER` or `IDENTIFYSHOPPER`. The response contains an **action** object that the frontend must execute.
3. **Client-side UI rendering** – The SFRA checkout page uses the Adyen Web SDK (`Checkout` component) 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`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/src/cartridges/int_adyen_SFRA/cartridge/adyen/utils/adyenHelper.js) constructs the required authentication payload. This function is invoked automatically when creating payment requests.

```javascript
// 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`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/src/cartridges/int_adyen_SFRA/cartridge/adyen/scripts/payments/adyenCheckout.js) calls this helper at line 156:

```javascript
// 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`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/src/cartridges/int_adyen_SFRA/cartridge/adyen/scripts/payments/adyenZeroAuth.js) at line 37:

```javascript
// 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`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/src/cartridges/int_adyen_SFRA/cartridge/adyen/scripts/hooks/payment/processor/middlewares/authorize.js) (lines 52-57), the logic checks the `isFinal` property:

```javascript
// 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`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/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`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/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:

```javascript
// 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:

```javascript
// 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

1. **Install the cartridge** – Ensure `int_adyen_SFRA` is added to your SFRA site-import and listed in [`metadata/site_import/services.xml`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/metadata/site_import/services.xml).
2. **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.
3. **Verify helper invocation** – Confirm that `AdyenHelper.add3DS2Data()` is called in [`adyenCheckout.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/adyenCheckout.js) (line 156) and [`adyenZeroAuth.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/adyenZeroAuth.js) (line 37). Only modify if you have overridden the default request creation.
4. **Handle action responses** – Ensure the [`authorize.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/authorize.js) middleware returns non-final responses to the controller. The default implementation already handles this.
5. **Implement frontend action handling** – Verify your checkout controller passes the `action` object from the server response to the Web SDK's `handleAction()` method.
6. **Test the flow** – Use the Playwright test suite or manual testing with 3DS2 test cards to confirm the `threeDSIframe` renders correctly and completes authentication.

## Summary

- **Server-side**: The `add3DS2Data` helper in [`adyenHelper.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/adyenHelper.js) injects `authenticationData` with `nativeThreeDS: 'preferred'` into all payment requests.
- **Middleware**: The [`authorize.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/authorize.js) middleware 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 `threeDSIframe` when `handleAction()` receives the server response.
- **Testing**: Playwright tests in `PaymentMethodsPage.mjs` verify the iframe interaction using `frameLocator("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`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/adyenCheckout.js) and [`adyenZeroAuth.js`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/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`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/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`](https://github.com/adyen/adyen-salesforce-commerce-cloud/blob/main/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.