Securing Stripe webhooks without authentication

The plot thickens

I agree with that. It’s for sure a risk - whether it’s worth it to secure the webhook isn’t obvious.

For what it’s worth, I’m currently sticking to the event + time check method with IP validation as I know that there’s no way for clients to get an event ID in basically all of my apps + client apps.

2 Likes

It was formerly there and was removed during an update to our API documentation. However, we will be adding the capability of this url parameter back into our documentation, so you should be able to see it there soon.

2 Likes

Hi @georgecollier ,

Thanks for the detailed explanation! I do have a question though. What’s the “only when” for “terminate this workflow” look like?

I know I should terminate it if no event could be found, but how to craft that conditional, I don’t know.

Would “result of step 1’s body id :is empty” work?

You assistance would be greatly appreciated!

Only when result of step 1’s returned an error is no should do the trick (the ‘check event API call nerds headers and continue workflow checkboxes enabled in API connector’

Do you know whether or where this got published in the Bubble manual? I don’t find it.

Great post! Thank you so much.

I tried this with LemonSqueezy and it seems to work just fine. Was wondering if there is anything LemonSqueezy specific to note?

I heard LemonSqueezy was built on top of stripe (not sure if true). Also, don’t mean to hijack this thread. Can delete if you want to keep it to Stripe only.

Thanks either way!

Do you need to expose the endpoint to use the webhook as only a trigger? If I don’t want to expose any endpoints at all, could I just refetch at certain intervals? It’s concerning that Bubble only allows you to generate a single type of API token (full admin access to everything) rather than dynamically allowing only limited access.

if the endopoint is not publicly accessible stripe can’t send requests to it. the solution is easy: don’t use the admin token for stripe webhooks and use only the data that you fetch from stripe using the api connector.

1 Like

Yep that’s what I think I’ll do using recurring workflows. Thanks!

Just stumbled upon this thread. Nice summary, @georgecollier . It seems to reiterate the basic strategy I outlined several years ago (and which I still use).

Having said that, I’ll be implementing a “relay” approach (not unlike this Cloudflare example) in an upcoming project. I made that decision based on the anticipated higher volume, higher dollar amounts, and higher risk profile of the transactions.

Anyway, it’s a shame Bubble doesn’t provide access to the raw request data (similar to the raw body text feature of API calls). It would make things simpler and easier. I like simple. :slightly_smiling_face:

1 Like

FYI, and sorry to bump an old thread, but I have created a Bubble feature request for a truly “Raw” body text for signature verification, as suggested by Bubble support. If we build support for this request it might expedite it. Or not, but one can only hope.

1 Like

Hey @georgecollier ,

I’m a bit late to the party, but this is the solution I came up with to deal with the problem. What are your thoughts on it? Does it work? Or should I add more stuff on top of it?

The final approach I’d recommend is fetching the event from Stripe based on the input event ID.

  1. Check event using webhook event ID
  2. Use result of step 1 in any data
  3. Make sure you only do stuff after checking you haven’t already processed this event ID (by storing any processed event IDs in the database)
1 Like

What’s wrong with checking subscriptions instead? I used this approach since it might be possible that another event occurred on the same subscription?

I feel like getting data for the current status of the subscription would simply give me the latest results, no?

You can do that too I guess, but that only works for simple implementations. Other users will want to do stuff when subscriptions update, are created, are deleted, etc, and checking the event gives you a good foundation to do all of that.

Hey guys, on top of the other solutions in this thread - the only other mechanism that I can recommend in authorising webhooks (and this applies to other services) is using Basic Auth instead of giving up App API key.

So instead of yourapp.com/api/?api_token=xzbcmnxbmnbc You can use
randomtoken:randomtoken@yourapp.com/api/

Then on your endpoint, detect headers and check if auth matches.

2 Likes

Can you explain this further?

Hey @randomanon , select the ‘detect headers’ on your API endpoint and then once initialized, it will have the headers:authorization value. Check that this is the value is consistent with what you’ve provided e.g. https://randomtoken:randomtoken@yourapp.com/api/

randomtoken:randomtoken is the value you customize.

This can be used in conjunction with other checks in the thread.

4 Likes

I again urge you all to add your comments/upvotes to the feature I suggested, which would make webhook signing possible in the way it’s intended to work, signature verification.

1 Like