Conversation
PayPal express checkout (product page, cart, mini-cart) bypasses the standard WC checkout pipeline. Hook into PayPal's CreateOrder AJAX endpoint to verify sessions before PayPal order creation. JS fetch interceptor injects the Blackbox session ID into ppc-create-order requests (same pattern as PayPal's reCAPTCHA module) and resets Blackbox after the fetch returns so subsequent payment attempts get a fresh session for evaluation.
e73871a to
2853976
Compare
PayPal checkout flows trigger double verification: PayPalCompat verifies during ppc-create-order (with session_id), then after approval, the standard protector fires again with an empty session_id (PayPal submits the checkout request directly, bypassing checkout JS). Add a `woocommerce_fraud_protection_should_verify_session` filter in SessionVerifier so extensions can skip redundant verify calls. PayPalCompat hooks this filter to skip verification when the payment method is a ppcp-* gateway AND either: - An approved PayPal order exists in the WC session (post-approval flow already verified at CreateOrder), or - The current request is ppc-create-order itself (PayPal's form validation fires the shortcode protector before our verify runs). Regular checkout with PayPal (e.g. Blocks "Place Order" without prior approval) is not skipped.
2853976 to
781afe9
Compare
leonardola
left a comment
There was a problem hiding this comment.
Test 1: Express from product page
I do see the paypal_express_order_creation being logged but I don't see the skip message. Weirdly on test 2 I do see the skip message.
Test 3: Express from classic checkout page
I don't see the paypal_express_order_creation but I do see woocommerce_checkout_order_processed
Before I continue would you check what could be going on?
|
Sure!
That should be okay, I updated the testing instructions to reflect that. The skip message happens when PayPal tries to call
That's weird. Are there any |
leonardola
left a comment
There was a problem hiding this comment.
Overall the changes look good. But I left a few comments and I couldn't correctly test the Apple/Google pay flows
Test 2: Express from cart page
I see the skipped log for blocks cart page but not for the shortcode cart page.
Test 4: Digital wallet (Apple Pay or Google Pay
I could not enable Apple or Google pay. An error happens on PayPal side which ends up blocking the setup.
| // Stored regardless of decision: Blackbox sessions are single-use, so | ||
| // re-verifying the same ID would fail rather than produce a fresh verdict. | ||
| if ( '' !== $session_id && function_exists( 'WC' ) && WC()->session ) { | ||
| WC()->session->set( self::VERIFIED_SESSION_ID_KEY, $session_id ); |
There was a problem hiding this comment.
I think these should be separate as they are serving different purposes: _fraud_protection_paypal_verified_session_id is an ephemeral WC session data to be used by the PayPal compat within a single checkout to detect redundant verification between ppc-create-order and the standard checkout protector, then it's irrelevant.
IMO, we shouldn't use the same key, but I'm happy to align the prefix if you'd like.
…express-integration
The fetch API accepts string, URL, or Request objects as the resource parameter. Use instanceof Request for Request objects and String() for URL objects to correctly extract the URL for interception matching.

Changes proposed in this Pull Request:
PayPal express checkout (product page, cart, mini-cart buttons) bypasses the standard WC checkout pipeline entirely — our checkout protectors never fire. This PR adds Blackbox fraud protection to these flows.
How it works:
paypal-express.js) patcheswindow.fetchto inject the Blackbox session ID intoppc-create-orderrequests and reset Blackbox after the response (same pattern PayPal uses for its own reCAPTCHA module).PayPalCompathookswoocommerce_paypal_payments_create_order_request_startedto verify the session before PayPal creates the order. On BLOCK, responds withwp_send_json_error(403).Skipping redundant verification:
Smart-button PayPal flows (express buttons, card fields, wallets) always go through
ppc-create-orderwherePayPalCompatverifies the session. Standard protectors (BlocksCheckoutProtector,ShortcodeCheckoutProtector) may also fire later in the same payment flow — these are redundant and should be skipped.A
woocommerce_fraud_protection_skip_session_verifyfilter inSessionVerifierlets extensions request skipping.PayPalCompathooks it to skip when:ppc-create-order— PayPal'sCreateOrderEndpointcallsCheckoutFormValidator::validate()which fireswoocommerce_checkout_process, triggeringShortcodeCheckoutProtectorbefore our verify action runs. Skip —PayPalCompathandles it next.ppc-create-order— for card/wallet flows on blocks checkout,blocks-checkout.jscaptures the session ID before PayPal'screateOrdercallback firesppc-create-order, so both calls use the same ID.ppcp.order) — post-approval express flow, already verified at CreateOrder (Blackbox was reset since, so session IDs won't match, but the session flag catches it).Flows that do NOT go through
ppc-create-order(Blocks "Place Order" withppcp-gatewayserver-side redirect, APM gateways) are NOT skipped.PayPal payment flow coverage (more details on the docs repo):
ppc-create-order?PayPalCompatPayPalCompatPayPalCompatPayPalCompatPayPalCompatBlocksCheckoutProtectorprocess_payment())Not yet covered (out of scope for this PR): PayPal payment data resolution (card details, wallet/payer identity).
Closes WOOSUBS-1447
paypal-verify-integration-demo.mov
How to test the changes in this Pull Request:
Prerequisites
Test 1: Express from product page
woo-fraud-protectionlogs: you should see apaypal_express_order_creationverify with a session IDTest 2: Express from cart page
woo-fraud-protectionlogs: you should see apaypal_express_order_creationverify with a session ID, then aSession verification skipped by ... filter for source: blocks_checkoutmessage (the skip means the redundant verify fromBlocksCheckoutProtectorwas correctly suppressed)Test 3: Express from classic checkout page
paypal_express_order_creationverify, then one or twoSession verification skipped ... for source: shortcode_checkoutmessages (PayPal'sCreateOrderEndpointmay triggerwoocommerce_checkout_processduring form validation and again on approval — both are correctly skipped)Test 4: Digital wallet (Apple Pay or Google Pay)
paypal_express_order_creationverify with a session ID. If the payment completes successfully, you should also see a skip message (same as Test 1).Test 5: Blocks checkout — "Place Order" with card (Debit & Credit Cards)
paypal_express_order_creationverify (card flows go throughppc-create-order), then aSession verification skipped ... for source: blocks_checkoutmessage — the skip works becauseblocks-checkout.jscaptured the same Blackbox session ID beforeppc-create-orderran, and the session ID match triggers the skipTest 6: Blocks checkout — "Place Order" with PayPal (non-express)
blocks_checkoutverify with a valid session ID — there should be NO skip message before it (this flow doesn't go throughppc-create-order, so it's verified normally byBlocksCheckoutProtector)Test 7: Local APM checkout (e.g. iDEAL)
shortcode_checkoutorblocks_checkoutverify with a valid session ID and theppcp-idealpayment method — there should be NO skip message (APMs don't go throughppc-create-order, so standard protectors verify normally)Test 8: Non-PayPal gateway unaffected
Test 9: Blocked session on express checkout
add_filter( 'woocommerce_fraud_protection_decision', fn() => 'block' );paypal_express_order_creationverify with ablockdecisionTest 10: Blackbox scripts on product/cart pages
blackbox-init.jsandpaypal-express.jsloading