#n0rlant1s-webhook-signature
1 messages ยท Page 1 of 1 (latest)
n0rlant1s-webhook-signature
This is the first part of my code where this is erroring:
@router.post('/webhook', response_model=Any)
async def webhook_received(
*,
db: Session = Depends(deps.get_db),
request: Request
):
# Auth: assumes webhook signing is configured.
# Nominally, Stripe also accepts non-signed webhooks.
signature = request.headers.get('stripe-signature')
request_data = await request.json()
raw_data = await request.body()
try:
event = stripe.Webhook.construct_event(payload=raw_data, sig_header=signature, secret=STRIPE_WEBHOOK_KEY)
data = event['data']
except Exception as e:
sentry_sdk.capture_exception(e)
return Response(status_code=500)
event_type = event['type']
data_object = data['object']
Hello! There are 2 things that can cause this problem
- Using the wrong webhook secret: not realizing that you have a different secret between the Stripe CLI locally and the real endpoint in the Dashboard for example
- Not passing the raw body that we give you. This is crucial as the signature verification only works on the exact payload we send you. If you tamper with it (or parts of your framework/code do) then it breaks signature verification
My webhook secret begins with whsec_wf -- that's correct right?
The raw body I have looks like this:
b'{\n "id": "evt_1LuI11C5XIuIJMyhD47AGbH1",\n "object": "event",\n "api_version": "2020-08-27",\n "created": 1666108058,\n "data": {\n "object": {\n "id": "ii_1LuI0yC5XIuIJMyh7auqdHkU",\n "object": "invoiceitem",\n "amount": -2844,\n "currency": "usd",\n "customer": "cus_MFyjhTrMNpJCxa",\n "date": 1666108056,\n "description": "Unused time on Starter Plan after 18 Oct 2022",\n "discountable": false,\n "discounts": [\n\n ],\n "invoice": "in_1LuI0yC5XIuIJMyh9Bntl0zh",\n "livemode": true,\n "metadata": {\n },\n "period": {\n "end": 1668734408,\n "start": 1666108056\n },\n "plan": {\n "id": "price_1LXQv6C5XIuIJMyhCDyk9TIh",\n "object": "plan",\n "active": true,\n "aggregate_usage": null,\n "amount": 2900,\n "amount_decimal": "2900",\n "billing_scheme": "per_unit",\n "created": 1660660744,\n "currency": "usd",\n "interval": "month",\n ...
``` -- it's expected in bytes right?
this is what I'm sending in payload=raw_data
yes the webhook secret starts with whsec_xxxx but you need to make sure it's exactly the secret you see in the Dashboard. And if you are certain you have the right one then it's the second issue and that's what you need to debug.
This is unfortunately really painful for developers because it could be "anything" in their stack that tampers with the data. What you can do is compare the raw payload you get between locally and the server
That's my confusion: It's all the exact same unfortunately -- but thanks for giving me some pointers ๐
so you get the same Event id evt_123 on both localhost and your server and the raw payload is exactly the same?
An example evt_[...] on my local is evt_1LuIA2C5XIuIJMyhqKbeyLCk, while it is evt_1LuI11C5XIuIJMyhW0dmvqFq on my prod.
Both are subscription updates
One subtle difference however: Description is null on prod, while non-null on local. Not sure why
Nevermind ๐ Found one in prod
the content of the property is not relevant. But my point is that you'd want to get the exact same Event to compare the raw payload
Ok it finally worked, but I didn't change anything significant at all -- just tried it a bunch of times. Also: I have a bunch of payments in prod that I would like to refund (I was testing this in prod) without hurting my payment reputation or for it to be flagged. Should I contact support to do it?
So strange that it suddenly worked
You should never test in production ever. Card networks don't like that, it's in our terms of services and docs
but if you have already, just refund, it won't hurt your reputation, but avoid doing this again
Yeah super strange -- I genuinely changed nothing ๐ฅฒ Will remember re: testing in prod. Thank you!