Stripe's webhook with django says: stripe.error.SignatureVerificationError
Asked Answered
M

6

8

I use the same code as in the stripe tutorial:

def webhook(request):
    payload = request.body
    sig_header = request.META['HTTP_STRIPE_SIGNATURE']
    event = None

    try:
        event = stripe.Webhook.construct_event(
            payload, sig_header, endpoint_secret
        )
    except ValueError as e:
        raise(e)
        return HttpResponse(status=400)
    except stripe.error.SignatureVerificationError as e:
        raise(e)
        return HttpResponse(status=400)

    # ...

but when I try to test the webhook with the stripe CLI (stripe trigger payment_intent.created) I have this error:

Internal Server Error: /payment/webhook/
Traceback (most recent call last):
  File "/home/rouizi/django-ecommerce/venv/lib/python3.6/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/home/rouizi/django-ecommerce/venv/lib/python3.6/site-packages/django/core/handlers/base.py", line 115, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/home/rouizi/django-ecommerce/venv/lib/python3.6/site-packages/django/core/handlers/base.py", line 113, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/home/rouizi/django-ecommerce/venv/lib/python3.6/site-packages/django/views/decorators/http.py", line 40, in inner
    return func(request, *args, **kwargs)
  File "/home/rouizi/django-ecommerce/venv/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "/home/rouizi/django-ecommerce/payment/views.py", line 99, in webhook
    raise(e)
  File "/home/rouizi/django-ecommerce/payment/views.py", line 88, in webhook
    payload, sig_header, endpoint_secret
  File "/home/rouizi/django-ecommerce/venv/lib/python3.6/site-packages/stripe/webhook.py", line 23, in construct_event
    WebhookSignature.verify_header(payload, sig_header, secret, tolerance)
  File "/home/rouizi/django-ecommerce/venv/lib/python3.6/site-packages/stripe/webhook.py", line 78, in verify_header
    payload,
stripe.error.SignatureVerificationError: No signatures found matching the expected signature for payload

I tried to decode the payload like this:

payload = request.body.decode('utf-8')

but I still have the same error.

Any ideas where the error may come from ?

Marmoreal answered 21/5, 2020 at 14:48 Comment(0)
U
9

For me the issue was resolved by decoding request.data.

payload = request.body.decode('utf-8')

I've just decided to note it as a separate answer, maybe someone missed this line in the question description.

Unroll answered 9/7, 2021 at 9:4 Comment(2)
This solved the problem! This answer should be marked as the solution.Australopithecus
This solved my problem too, it would be nice to know why this is happening. No time to investigate it myself right now.Anabasis
P
9

It turns out, that when creating webhook in test mode it gives you webhook secret same as for the CLI.

You need to use this secret as webhook secret as stated in other comments. enter image description here

Petulant answered 11/3, 2022 at 14:43 Comment(1)
Thanks, I actually used the webhook id instead of the secret.Twice
G
3

In a test mode and in a live mode — all three keys are different:

# web_app/settings.py
## STRIPE LIVE
STRIPE_ENDPOINT_SECRET = 'whsec_******'
STRIPE_PUBLISHABLE_KEY =  'pk_live_*******'
STRIPE_SECRET_KEY = 'sk_live_******'

Hence, I would suggest you to check if you used the correct ENDPOINT secret that is also different for the Live mode, even if the webhook url is the same as for the Test mode:

enter image description here

Gerrald answered 23/10, 2021 at 23:18 Comment(0)
T
0

It's important that you're passing the raw request body into construct_event and that nothing has parsed or modified it earlier in your stack.

An important difference from the example you reference is how the header and body are accessed. You also do not show where your endpoint_secret is coming from. Have you checked to make sure all inputs are what you expect?

If you have, try recreating the signature manually using the steps documented.

Thelmathem answered 21/5, 2020 at 15:14 Comment(3)
I am passing the raw request body into construct_event, if I do print(type(payload)) I have in response: <class 'bytes'> and my endpoint_secret is coming from settings: endpoint_secret = settings.ENDPOINT_SECRET, and for recreating the signature I don't know how to verify the signature manually. I'm still stuckMarmoreal
If you're sure that request.body is the raw request body, double check that your secret is being loaded (ie, log the value to confirm) and that it is the correct secret for the endpoint. Note in particular that even if you have the same URL set up for live and test mode, they are treated as distinct endpoints with different signing secrets. The steps for reproducing the signature are described in the final link in my answer.Thelmathem
I found where the issue came from. To test my webhook I used the endpoint secret that is in my webhook settings in the Developer Dashboard while I was using the stripe CLI instead of using the endpoint secret that is print when I run stripe listen. I spent hours trying to figure out where the issue was. I don't know if it happened only to me but I thing in the documentation they should draw attention to this point instead of making a comment. Thank you for your helpMarmoreal
I
0

In my case, the problem solved after I re-created the endpoint secret.

stripe.error.SignatureVerificationError

The exception, no longer raised. It turned out, that the endpoint secret was set to be expired. So you may double check the endpoint secret.

Irreducible answered 6/8, 2021 at 8:20 Comment(0)
T
0

For anyone who had to go through this similar issues. I followed the following steps to resolve it, Step 1:

payload = request.body.decode('utf-8')

Step 2: The webhook_endpoint_secret provided is not what you're going to use to verify the endpoint, you have to use the signing_secret of the dashboard. I'm still in testing, but i don't know if this is the same for live mode.

Tenuto answered 1/4, 2023 at 11:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.