Fixed That Sneaky Webhook Bug That Was Silently Failing All Along
Had one of those debugging sessions today where the bug turned out to be way more interesting than expected.
Started investigating why Stripe webhooks weren't reaching AdminStack properly. Added a bunch of verbose logging, tested the endpoint manually (worked fine), checked middleware auth exclusions (all good), verified deployment config... everything looked right.
Then I did a full audit of the webhook handler and found not just one bug, but SIX issues:
The main culprit: When webhook signature verification failed, my verifyWebhookSource() function returned null. Then my handler checked if (webhookSource && ...) which skipped the MemStack Pro logic entirely. But here's the kicker — it still returned a 200 status, so Stripe thought everything was fine and stopped trying.
Classic silent failure. The worst kind of bug.
While I was at it, I found a bunch of other security issues:
- JSON was being parsed before signature verification
- The product revenue handler could intercept MemStack Pro events
- Error handling returned 200 instead of 500, preventing Stripe retries
- Some paths had no signature verification at all
Fixed all of them in one go. Now signature verification happens first, no exceptions. Failed signatures return 400 (so Stripe stops retrying), and actual errors return 500 (so Stripe keeps trying).
Other fixes today:
Fixed the MemStack Pro session nudge that wasn't showing up in Claude. Turns out my echo output was too plain — Claude received it but didn't surface it to the user. Switched to a cat heredoc with IMPORTANT: prefix and explicit directive language. Much better.
Also added a delete button to the licenses page with proper confirmation dialog. Sometimes you need to permanently remove a license, not just revoke it.
What's next:
The webhook fix is deployed but I need to trigger a live test event to confirm the end-to-end flow works. My money's on the MEMSTACK_PRO_STRIPE_WEBHOOK_SECRET environment variable being missing or wrong in production — that would explain why signatures were failing silently.
At least now when something's broken, it'll actually tell me instead of pretending everything's fine.