'Why does Stripe webhook work in test mode but not live: error 403 CSRF verification failed. Request aborted
I have a django website with shopping cart hooked up to Stripe. On successful payment, the system emails the customer with their purchased electronic products (links to videos and online meetings).
This works perfectly when Stripe is in test mode, but when live, the webhook that triggers the email fails to complete. I don't think it is a browser cookie problem as it happened with a remote user, not just me on my own computer.
I assume it is something to do with CRSRF_Token but I don't have the knowledge or experience to understand it yet. Any help would be greatly appreciated. Code below.
Views:
@csrf_exempt
def stripe_webhook(request):
payload = request.body
sig_header = request.META['HTTP_STRIPE_SIGNATURE']
event = None
try:
event = stripe.Webhook.construct_event(
payload, sig_header, settings.STRIPE_WEBHOOK_SECRET
)
except ValueError as e:
# Invalid payload
return HttpResponse(status=400)
except stripe.error.SignatureVerificationError as e:
# Invalid signature
return HttpResponse(status=400)
# Handle the checkout.session.completed event
if event['type'] == 'checkout.session.completed':
session = event['data']['object']
# Save an order in your database, marked as 'awaiting payment'
create_order(session)
# Check if the order is already paid (e.g., from a card payment)
#
# A delayed notification payment will have an `unpaid` status, as
# you're still waiting for funds to be transferred from the customer's
# account.
if session.payment_status == "paid":
# Fulfill the purchase
fulfill_order(session)
elif event['type'] == 'checkout.session.async_payment_succeeded':
session = event['data']['object']
# Fulfill the purchase
fulfill_order(session)
elif event['type'] == 'checkout.session.async_payment_failed':
session = event['data']['object']
# Send an email to the customer asking them to retry their order
email_customer_about_failed_payment(session)
# Passed signature verification
return HttpResponse(status=200)
def create_order(session):
print(">>>>>>>>>>>>>>>>create_order")
customer_email = session["customer_details"]["email"]
transaction_id = session["payment_intent"]
customer = Customer.objects.get(
email=customer_email
)
# get or create order
try:
print("tryingg")
order = Order.objects.get(transaction_id=transaction_id)
except Order.DoesNotExist:
print("exception")
order = Order(customer=customer, complete=False,
order_status='W', transaction_id=transaction_id)
order.save()
digital_products_url = []
product_info = []
for key, value in session["metadata"].items():
if "item" in key:
item_list = value.split(",")
product_id = item_list[0]
product_quantity = item_list[1]
product = Product.objects.get(id=product_id)
if product.digital:
digital_products_url.append(product.product_url)
product_info.append({
"name": product.name,
"event_type": product.event_type,
"product_url" : product.product_url,
"meeting_passcode" : product.meeting_passcode,
"subtitle" : product.subtitle,
"intro_text" : product.intro_text,
"short_description" : product.short_description,
"price" : product.price,
"image" : product.image,
"start_time" : product.start_time,
"duration" : product.duration,
"description" : product.description
})
orderItem = OrderItem.objects.create(
product=product,
order=order,
quantity=product_quantity,
)
session["metadata"]["digital_product_url"] = digital_products_url
session["metadata"]["product_info"] = product_info
def fulfill_order(session):
print("fulfill_order")
transaction_id = session["payment_intent"]
order = Order.objects.get(
transaction_id=transaction_id
)
order.complete = True
order.order_status = 'P'
order.save()
digital_products_url = session["metadata"]["digital_product_url"]
customer_email = session["customer_details"]["email"]
customer = Customer.objects.get(
email=customer_email
)
if order.shipping == True:
ShippingAddress.objects.create(
customer=customer,
order=order,
address=session["metadata"]['address'],
city=session["metadata"]['city'],
state=session["metadata"]['state'],
zipcode=session["metadata"]['zipcode'],
)
if digital_products_url:
# send email to user
try:
from_email = settings.EMAIL_HOST_USER
to_email = [customer_email]
# import html message.html file
html_template = 'store/mail.html'
html_message = render_to_string(
html_template, {'context': digital_products_url, "product_info": session["metadata"]["product_info"] })
message = EmailMessage(
'North Wales Early Music Festival', html_message, from_email, to_email)
# this is required because there is no plain text email message
message.content_subtype = 'html'
message.send()
order.email_sent = True
order.save()
except Exception as e:
order.email_sent = False
order.save()
Checkout Utility code which contains alos uses csrf_token:
var form = document.getElementById('form');
form.addEventListener('submit', function (e) {
e.preventDefault();
console.log('Form Submitted...');
payment_btn = document.getElementById('make-payment');
payment_btn.click();
// document.getElementById('form-button').classList.add('hidden');
// document.getElementById('payment-info').classList.remove('hidden');
});
document
.getElementById('make-payment')
.addEventListener('click', function (e) {
submitFormData();
});
function submitFormData() {
console.log('Payment button clicked');
var userFormData = {
name: null,
email: null,
total: total,
};
var shippingInfo = {
address: null,
city: null,
state: null,
zipcode: null,
};
if (shipping != 'False') {
shippingInfo.address = form.address.value;
shippingInfo.city = form.city.value;
shippingInfo.state = form.state.value;
shippingInfo.zipcode = form.zipcode.value;
}
if (user == 'AnonymousUser') {
userFormData.name = form.name.value;
userFormData.email = form.email.value;
}
console.log('Shipping Info:', shippingInfo);
console.log('User Info:', userFormData);
var url = '/create-checkout-session/';
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'applicaiton/json',
'X-CSRFToken': csrftoken,
},
body: JSON.stringify({ form: userFormData, shipping: shippingInfo}),
})
.then(function (response) {
return response.json();
})
.then(function (session) {
if (session.status == "success"){
// delete cookie
cart = {};
document.cookie = 'cart=' + JSON.stringify(cart) + ';domain=;path=/';
console.log("cart deleted")
}
return stripe.redirectToCheckout({ sessionId: session.id });
})
.then(function (result) {
// If redirectToCheckout fails due to a browser or network
// error, you should display the localized error message to your
// customer using error.message.
if (result.error) {
alert(result.error.message);
}
})
.catch(function (error) {
console.error("Error:", error);
});
}
</script>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
