[Video Tutorial] How to configure Stripe payment webhooks for bubble backend


#1

Stripe Webhooks allow your application backend to be notified when some event such as subscription charge failure, refunds, etc occurs in your Stripe account.
This tutorial shows how to setup a Stripe webhook that notifies a Bubble backend when some events occur.

For a tutorial on how to integrate stripe in your dropsource app without using any backend see the post


#2

@seanhoots The means of using webhooks here is very resourceful. Allowing Stripe and Bubble to work outside of the purview of the app is an excellent way to build secure cross communication techniques as well as make everything work more reactive. This is really valuable!


#3

@wade For security reasons I will personally advice not to use webhooks and only use webhooks only when it is absolutely necessary for behind-the-scenes transactions.
Stripe actually states this in their documentation.

Most Stripe requests (e.g., creating charges or refunds) generate results that are reported synchronously to your code. These don’t require webhooks for verification.

The reason for using webhooks only when it is necessary (for example processing a failed subscription ) is that stripe webhook calls are not authenticated so there is a security risk.

  • The first risk is that a malicious agent can send request to your endpoint to make it appear it is coming from Stripe. Because of this stripe adds a signature in the header of request that you can use for verification.

  • The second is a replay attack whereby an attacker intercepts a valid payload (webhook request) and its signature, then re-transmits them.
    Again here stripe add some timestamp to help you in the verification.

But all these will require some effort from the developer in verifying the payload to avoid any attack.

Here is some practical simple approach to mitigate these weebhook risks without having to deal with the complexities of signatures and hashing (especially for no coders).

  1. You should only use the event id sent in a webhook and should request the remaining details from the API directly. Every stripe webhook request comes with a unique event id. So instead of consuming all the request data sent by stripe as i showed in the video, only accept the event id, then make a request to Stripe yourself using this id. If a malicious agent had crafted this payload the id wouldn’t exist in stripe so you will know it is fake.

  2. Create a table in your backend to record all events processed and never process an event twice. That is, anytime you receive an event from a stripe webhook, get only the id as explained in point 1 above, then check if the id is in your database. If it does, don’t process it. If it doesn’t make a call to stripe with the id to get the details for that event. This will guard against replay-attacks.

In Bubble the two approaches I explained above can easily be implemented. In fact this is the exact same approach the bubble company themselves use in processing the stripe webhooks (they use stripe for all their payments).

It is for these extra work required in dealing with webhooks that I advice to only use webhooks when necessary.
In most use cases you wouldn’t need to use webhooks unless you’re using stripe subscriptions in your app.

I only created this webhook tutorial because @markpiller wanted me to show him that this was possible and easy to do in Bubble.


#4

Hi @seanhoots, after watching the video it made me think that you and I have different criteria for calling something easy. I am sure some people will find it useful though, so there’s definitely value in it.

Cheers,
Mark


#5

Hi @markpiller, in my opinion “easy” is a very subjective term which normally depends on what one is familiar with.

If you follow our conversations you will realize I’ve never tried to pitch Bubble against Backendless, you rather have and it’s understandable given your vested interest in Backendless. I don’t have any allegiance.

Something doesn’t need to be easier than the other to be useful.
Both can be easy at the same time, after all easy is very subjective.