From 53229c36b1642ca3846e6cf109f9175d6a6f3b59 Mon Sep 17 00:00:00 2001 From: nobody Date: Fri, 7 Nov 2025 13:50:23 +0000 Subject: [PATCH 1/2] Empty commit to allow auto PR creation From ac35c26c831cb5535a9af342980d37de25e3f860 Mon Sep 17 00:00:00 2001 From: chrisjsimpson Date: Fri, 7 Nov 2025 14:29:47 +0000 Subject: [PATCH 2/2] Fix #1474 enforce HTTPS URLs for Stripe API calls in live mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stripe requires all URLs (return_url, refresh_url, success_url, cancel_url) to use HTTPS when making API calls in live mode. This fixes the error: "Livemode requests must always be redirected via HTTPS." Changes: - Modified _generate_account_link() in admin blueprint to use HTTPS URLs when stripe_livemode() is True - Modified stripe_create_checkout_session() in checkout blueprint to use HTTPS for success/cancel URLs - Modified account() in subscriber blueprint to use HTTPS for payment method update URLs - All url_for() calls now include _scheme='https' parameter when in live mode 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- subscribie/blueprints/admin/__init__.py | 11 +++++++---- subscribie/blueprints/checkout/__init__.py | 10 +++++++--- subscribie/blueprints/subscriber/__init__.py | 8 ++++++-- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/subscribie/blueprints/admin/__init__.py b/subscribie/blueprints/admin/__init__.py index 7c62c24c..6057bc5a 100644 --- a/subscribie/blueprints/admin/__init__.py +++ b/subscribie/blueprints/admin/__init__.py @@ -1391,18 +1391,21 @@ def _generate_account_link(account_id): """ From the Stripe Docs: A user that is redirected to your return_url might not have completed the - onboarding process. Use the /v1/accounts endpoint to retrieve the user’s + onboarding process. Use the /v1/accounts endpoint to retrieve the user's account and check for charges_enabled. If the account is not fully onboarded, provide UI prompts to allow the user to continue onboarding later. The user can complete their account activation through a new account link (generated by your integration). You can check the state of the details_submitted - parameter on their account to see if they’ve completed the onboarding process. + parameter on their account to see if they've completed the onboarding process. """ + # Stripe requires HTTPS URLs when in live mode + url_scheme = 'https' if stripe_livemode() else None + account_link = stripe.AccountLink.create( type="account_onboarding", account=account_id, - refresh_url=url_for("admin.stripe_connect", refresh="refresh", _external=True), - return_url=url_for("admin.stripe_connect", success="success", _external=True), + refresh_url=url_for("admin.stripe_connect", refresh="refresh", _external=True, _scheme=url_scheme), + return_url=url_for("admin.stripe_connect", success="success", _external=True, _scheme=url_scheme), ) return account_link.url diff --git a/subscribie/blueprints/checkout/__init__.py b/subscribie/blueprints/checkout/__init__.py index 9cea9d89..4a4d9360 100644 --- a/subscribie/blueprints/checkout/__init__.py +++ b/subscribie/blueprints/checkout/__init__.py @@ -458,7 +458,11 @@ def stripe_create_checkout_session(): person = Person.query.get(session["person_id"]) charge["currency"] = currency_code payment_method_types = ["card"] - cancel_url = url_for("checkout.order_summary", _external=True) + + # Stripe requires HTTPS URLs when in live mode + url_scheme = 'https' if get_stripe_livemode() else None + + cancel_url = url_for("checkout.order_summary", _external=True, _scheme=url_scheme) mode = "payment" payment_intent_data = {} # Build line_items array depending on plan requirements @@ -488,7 +492,7 @@ def stripe_create_checkout_session(): charge["sell_price"] = plan.getSellPrice(currency_code) charge["interval_amount"] = plan.getIntervalAmount(currency_code) success_url = url_for( - "checkout.instant_payment_complete", _external=True, plan=plan.uuid + "checkout.instant_payment_complete", _external=True, plan=plan.uuid, _scheme=url_scheme ) if plan.requirements.subscription: @@ -564,7 +568,7 @@ def stripe_create_checkout_session(): ) elif is_donation is True: - success_url = url_for("checkout.instant_payment_complete", _external=True) + success_url = url_for("checkout.instant_payment_complete", _external=True, _scheme=url_scheme) donation_amount = int(session["donation_amount"] * 100) line_items.append( { diff --git a/subscribie/blueprints/subscriber/__init__.py b/subscribie/blueprints/subscriber/__init__.py index 68037a82..646f84cc 100644 --- a/subscribie/blueprints/subscriber/__init__.py +++ b/subscribie/blueprints/subscriber/__init__.py @@ -39,6 +39,7 @@ get_stripe_connect_account_id, get_stripe_publishable_key, get_stripe_invoices, + get_stripe_livemode, ) from subscribie.email import EmailMessageQueue from jinja2 import Template @@ -264,6 +265,9 @@ def account(): stripe_customer_id, stripe_account=stripe_connect_account_id ) + # Stripe requires HTTPS URLs when in live mode + url_scheme = 'https' if get_stripe_livemode() else None + stripe_session = stripe.checkout.Session.create( stripe_account=stripe_connect_account_id, payment_method_types=["card"], @@ -272,9 +276,9 @@ def account(): setup_intent_data={ "metadata": {"subscription_id": stripe_subscription.id} }, - success_url=url_for("subscriber.account", _external=True) + success_url=url_for("subscriber.account", _external=True, _scheme=url_scheme) + "?stripe_session_id={CHECKOUT_SESSION_ID}", - cancel_url=url_for("subscriber.account", _external=True), + cancel_url=url_for("subscriber.account", _external=True, _scheme=url_scheme), ) if request.args.get("stripe_session_id"): # Process stripe update payment request