Skip to content

Harden Stripe webhook endpoint and correct Flask integration points#345

Open
Copilot wants to merge 4 commits into
mainfrom
copilot/fix-webhook-signature-verification
Open

Harden Stripe webhook endpoint and correct Flask integration points#345
Copilot wants to merge 4 commits into
mainfrom
copilot/fix-webhook-signature-verification

Conversation

Copilot AI commented May 27, 2026

Copy link
Copy Markdown
Contributor

The webhook handler had integration defects (Flask(__name__), Stripe-Signature header usage, and __main__ guard) and lacked strict Stripe signature validation. This PR introduces a production-safe /api/webhook flow that rejects untrusted requests before event handling.

  • Webhook contract and verification

    • Adds POST /api/webhook in api/index.py.
    • Verifies incoming events with stripe.Webhook.construct_event(payload, sig_header, STRIPE_ENDPOINT_SECRET).
    • Returns explicit error responses for missing endpoint secret, missing signature header, invalid payload, and signature verification failures.
  • Event handling baseline

    • Normalizes event routing via event_type.
    • Adds initial handling path for payment_intent.succeeded with server-side logging hook for downstream async processing.
  • Dependency alignment

    • Adds Stripe SDK to API dependencies in api/requirements.txt (stripe==11.6.0).
  • Webhook behavior coverage

    • Adds focused unit tests in tests/test_api_webhook.py for:
      • missing signature header
      • invalid payload
      • valid payment_intent.succeeded request path
sig_header = request.headers.get("Stripe-Signature")
event = stripe.Webhook.construct_event(payload, sig_header, STRIPE_ENDPOINT_SECRET)
event_type = event.get("type")

if event_type == "payment_intent.succeeded":
    print("[tryonyou] Stripe payment_intent.succeeded received", flush=True)

@vercel

vercel Bot commented May 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
tryonyou-app Error Error May 27, 2026 1:15pm
tryonyou-app-1776375445 Error Error May 27, 2026 1:15pm
tryonyou-app-work Error Error May 27, 2026 1:15pm
tryonyou-pilot Error Error May 27, 2026 1:15pm
workspace Error Error May 27, 2026 1:15pm

@LVT-ENG LVT-ENG left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes

@LVT-ENG

LVT-ENG commented May 27, 2026

Copy link
Copy Markdown
Member

@cursoragent

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens the Vercel-hosted Flask API by adding a Stripe webhook endpoint that performs strict signature verification before handling events, and adds initial event routing plus unit tests to validate webhook behavior.

Changes:

  • Adds POST /api/webhook to api/index.py, validating the Stripe-Signature header and verifying events via stripe.Webhook.construct_event(...).
  • Introduces baseline handling for payment_intent.succeeded (currently via server-side logging).
  • Adds Stripe SDK dependency (stripe==11.6.0) and unit tests covering key webhook request paths.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
api/index.py Adds the Stripe webhook route with signature verification and basic event routing.
api/requirements.txt Adds the Stripe Python SDK dependency needed for webhook verification.
tests/test_api_webhook.py Adds unit tests for the new webhook endpoint behavior and error paths.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread api/index.py
if event_type == "payment_intent.succeeded":
print("[tryonyou] Stripe payment_intent.succeeded received", flush=True)

return _json_ok({"status": "success"}, 200)
Comment thread tests/test_api_webhook.py
Comment on lines +18 to +44
def test_invalid_payload(self):
with patch.object(index, "STRIPE_ENDPOINT_SECRET", "whsec_test"):
with patch("api.index.stripe.Webhook.construct_event", side_effect=ValueError):
response = self.client.post(
"/api/webhook",
data=b"{bad json}",
headers={"Stripe-Signature": "t=1,v1=fake"},
)

self.assertEqual(response.status_code, 400)
self.assertIn("invalid payload", response.get_data(as_text=True))

def test_payment_intent_succeeded(self):
event = {"type": "payment_intent.succeeded", "data": {"object": {"id": "pi_123"}}}
with patch.object(index, "STRIPE_ENDPOINT_SECRET", "whsec_test"):
with patch("api.index.stripe.Webhook.construct_event", return_value=event):
with patch("api.index.print") as print_mock:
response = self.client.post(
"/api/webhook",
data=b"{}",
headers={"Stripe-Signature": "t=1,v1=fake"},
)

self.assertEqual(response.status_code, 200)
self.assertIn("success", response.get_data(as_text=True))
print_mock.assert_called_with("[tryonyou] Stripe payment_intent.succeeded received", flush=True)

@LVT-ENG LVT-ENG left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes

@LVT-ENG LVT-ENG left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes

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