Stripe: No signatures found matching the expected signature for payload using Django

Question:

I am getting the below error while Stripe calling the defined Web hook

No signatures found matching the expected signature for payload

I am following this article: https://stripe.com/docs/billing/subscriptions/checkout#provision-and-monitor

And I have following code:

@csrf_exempt
def saaswebhookview(request):
    try:
        stripe.api_key = settings.STRIPE_SECRET_KEY
        webhook_secret = 'stripe_key'
        request_data = request.POST
        if webhook_secret:
            try:
                signature = request.headers.get('stripe-signature')
                # signature = request.META['stripe-signature']
                event = stripe.Webhook.construct_event(
                    payload=request.POST, sig_header=signature, secret=webhook_secret)
                data = event['data']
            except Exception as e:
                print(str(e))
                return JsonResponse({'status': 'error', 'error': str(e)})
            event_type = event['type']
        else:
            data = request_data['data']
            event_type = request_data['type']
        data_object = data['object']
        if event_type == 'checkout.session.completed':
            print(data)
        elif event_type == 'invoice.paid':
            print(data)
        elif event_type == 'invoice.payment_failed':
            print(data)
        else:
            print('Unhandled event type {}'.format(event_type))
        return JsonResponse({'status': 'success'}, safe=False)
    except Exception as e:
        return JsonResponse({'status': 'success', 'error': str(e)}, safe=False)

But strangely this throws me the error don’t know why?

Asked By: FightWithCode

||

Answers:

The Stripe library requires the raw body of the webhook request for signature verification to work. It looks like you’re supplying request.POST, which is an altered version of the body.

If you use request.body instead it should work as expected.

Answered By: Justin Michael

Script to verify your Stripe Webhook API with generated signature

import hmac
import time
from hashlib import sha256

import requests
import stripe

webhook_url = 'https://your-site/api/stripe/webhook/'
stripe_secret = 'YOUR_STRIPE_WEBHOOK_SIGN_SECRET'  # whsec_..
webhook_json_file = 'PATH_TO_JSON_FILE_WITH_WH_DATA/webhook_example.json'


def generate_stripe_signature_header(payload: str):
    timestamp_utc = int(time.time())
    signed_payload = "%d.%s" % (timestamp_utc, payload)
    v1_sig = compute_signature(signed_payload, secret=stripe_secret)
    return f't={timestamp_utc},v1={v1_sig}'


def compute_signature(payload: str, secret):
    """Take from stripe"""
    mac = hmac.new(
        secret.encode("utf-8"),
        msg=payload.encode("utf-8"),
        digestmod=sha256,
    )
    return mac.hexdigest()


with open(webhook_json_file, 'r') as f:
    payload = f.read()

signature = generate_stripe_signature_header(payload=payload)

headers = {
    'STRIPE-SIGNATURE': signature,  
    'Content-Type': 'application/json',
}

session = requests.Session()
session.headers.update(**headers)
response = session.post(webhook_url, data=payload)

print(response.content)
print(response.status_code)
response.raise_for_status()

P.S. IF you want to use it for unit tests / Django Test Client, you need to add HTTP_ prefix to the signature header

signature = generate_stripe_signature_header(payload=payload)
headers = {
    'HTTP_STRIPE-SIGNATURE': signature,  
    'Content-Type': 'application/json',
}
self.client.post(webhook_url, data=payload, **headers)
Answered By: pymen

In my case, for to resolve my problem I decoding the body:

payload = request.body.decode('utf-8')
Answered By: Andrés Sapatanga

In my case I was using the secret from the stripe-cli.

Instead, go the the webhook section, click your webhook and finally click reveal secret. This will show the secret you want.

Answered By: S.D.

The answer provided by pymen worked perfectly when trying to use it for unit tests / Django Test Client. However, I kept getting the following error: "AttributeError: ‘str’ object has no attribute ‘items’" and i fixed it by adding content_type=’application/json’ in self.client.post.

self.client.post(webhook_url, data=payload, content_type='application/json', **headers)
Answered By: armzy
request_body = request.body

request_data = request.data

...

event = stripe.Webhook.construct_event(payload=request_body, sig_header=signature, secret=webhook_secret)
Answered By: SATYA
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.