Skip to content

Add rate-limit/cooldown to Stripe API requests after 401 errors #4497

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

diegocurbelo
Copy link
Member

@diegocurbelo diegocurbelo commented Jul 15, 2025

Fixes STRIPE-586

Changes proposed in this Pull Request:

When the UPE Gateway is instantiated, every available payment method is instantiated, and each one reads the account country to see if the PM can be enabled or not.

This is usually not a problem because we have a static cache and a database cache in place, so we only make one API call. However, when the Stripe keys are invalid and the account cache expires, each attempt to read the account country makes a Stripe API call, which means ~25 requests every time the UPE Gateway is instantiated.

This PR prevents Stripe API calls after several consecutive 401 (Unauthorized) responses (5) by detecting invalid API keys, storing a flag, and blocking further requests for 2 hours or until the keys are updated.

This improves performance and user feedback by avoiding repeated failed attempts and indicating a disconnected state in the UI.

NOTE: We should not be displaying the Invalid API key... error message to customers; I have created a follow-up issue STRIPE-632 for this.

Testing instructions

  1. Navigate to WP-Admin > WooCommerce > Settings > Payments, and select the Stripe option from the list
  2. Go to the Settings tab and make sure the account is correctly connected:
    Screenshot 2025-07-21 at 15 49 40
  3. Replace the API keys with an invalid value:
    wp option patch update woocommerce_stripe_settings test_secret_key 'sk_test_INVALID'
  4. Go to the Store, go to any product page, and attempt to place an order using Google Pay; you should get this error:
    Screenshot 2025-07-21 at 15 54 57
  5. Retry the purchase two more times (each attempt makes two calls to Stripe, so it will go over the limit (5))
  6. Go back to WP-Admin and into the plugin Settings tab and make sure the account connection error message is displayed:
    Screenshot 2025-07-21 at 16 41 19
  7. Check that an error entry was logged to the plugin logs
    Go toWooCommerce > Status > Los and then click woocommerce-gateway-stripe:
    Screenshot 2025-07-21 at 16 36 46
  8. Click Configure connection and make sure the Account status is Disconnected
    Screenshot 2025-05-16 at 13 16 59
  9. Click the Create or connect a test account button, a re-connect your account
  10. Check that after returning to the WP-Admin dashboard, the top notice is no longer present, and the account status section has been restored:
    Screenshot 2025-05-16 at 13 25 43

  • Covered with tests (or have a good reason not to test in description ☝️)
  • Tested on mobile (or does not apply)

Changelog entry

  • This Pull Request does not require a changelog entry. (Comment required below)
Changelog Entry Comment

Comment

Post merge

@diegocurbelo diegocurbelo self-assigned this Jul 18, 2025
@diegocurbelo diegocurbelo marked this pull request as ready for review July 21, 2025 20:23
@diegocurbelo diegocurbelo requested review from a team, daledupreez and Mayisha and removed request for a team July 21, 2025 20:28
Copy link
Contributor

@daledupreez daledupreez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some feedback based on inspection.

@diegocurbelo diegocurbelo requested a review from daledupreez July 23, 2025 04:31
Copy link
Contributor

@Mayisha Mayisha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works as described 👍

Copy link
Contributor

@daledupreez daledupreez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes look good to me and test well.

I have one non-blocking comment that we should think about, but I am not sure if we need to take action on it.

Comment on lines +341 to 343
if ( null !== $invalid_api_key_error_count ) {
WC_Stripe_Database_Cache::delete( self::INVALID_API_KEY_ERROR_COUNT_CACHE_KEY );
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not blocking, but do we want to confirm we got a 2xx response code before we clear this cache? I don't think it's a big thing either way, but clearing the cache for any non-401 response feels like it may be the wrong approach in some situations, e.g. 500 or 403 responses.

@diegocurbelo diegocurbelo enabled auto-merge (squash) July 24, 2025 13:11
@diegocurbelo
Copy link
Member Author

The WC_Stripe_Subscriptions_Helper_Test::test_is_subscription_payment_method_detached was failing because of the 401 rate limiter. The underlying problem is that in several tests, we are not properly mocking the Stripe API calls (either by mocking methods or by using pre_http_request).

That fix is outside the scope of this PR, and I'll fix it in a new PR. For now, I updated the tearDown methods to reset the rate-limit check (INVALID_API_KEY_ERROR_COUNT_CACHE_KEY) with a TODO comment:

// The tests in this file do not mock ALL the calls to the Stripe API, and as we use mocked API keys, they trigger the 401 rate-limiter,
// this is not a problem for these tests as they don't depend on the responses.
//
// TODO: Remove this once we've mocked all calls to the Stripe API (either using the pre_http_request filter, or by using a mocked WC_Stripe_API class).
WC_Stripe_Database_Cache::delete( WC_Stripe_API::INVALID_API_KEY_ERROR_COUNT_CACHE_KEY );

@diegocurbelo diegocurbelo merged commit a81fd09 into develop Jul 24, 2025
47 of 48 checks passed
@diegocurbelo diegocurbelo deleted the fix/586-disable-gateway-after-several-401-responses branch July 24, 2025 16:14
Copy link

📈 PHP Unit Code Coverage Report

Package Line Rate Health
includes/class-wc-stripe-api.php 64%
includes/connect/class-wc-stripe-connect.php 6%
Summary 46% (7762 / 16993)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants