Skip to content

fix(stripe): trim whitespace from webhook secret and signature#565

Merged
equationalapplications merged 2 commits into
stagingfrom
fix/stripe-webhook-secret-whitespace
Jul 20, 2026
Merged

fix(stripe): trim whitespace from webhook secret and signature#565
equationalapplications merged 2 commits into
stagingfrom
fix/stripe-webhook-secret-whitespace

Conversation

@equationalapplications

Copy link
Copy Markdown
Owner

Incident

The first paying customer paid $10 but received no credits (stuck at signup credits, free tier). Root cause: the STRIPE_WEBHOOK_SECRET value in Secret Manager had a trailing newline. It was passed raw into stripe.webhooks.constructEvent, so Stripe rejected every live webhook with a signature-verification error (400) — the credit-grant path never ran, silently, for all payers.

Stripe's own error confirmed it: "the provided signing secret contains whitespace…".

Fix

  • Trim STRIPE_WEBHOOK_SECRET and the stripe-signature header before verification (mirrors the existing validateAndNormalizeStripeSecretKey used for the API key).
  • Regression test: newline-suffixed secret + padded signature must still verify (asserts the trimmed values reach constructEvent). Red→green confirmed; full stripeWebhook suite passes (27/27), build clean.
  • Document STRIPE_WEBHOOK_SECRET in functions/.env.example as a Secret-Manager value that must carry no trailing whitespace.

Operational steps done outside this PR (prod)

  • Re-added STRIPE_WEBHOOK_SECRET cleanly (rolled the endpoint's signing secret) and redeployed stripeWebhook. Verified the deployed function accepts a correctly-signed request (200).
  • Recovered the affected customer (subscription canceled, credits adjusted).
  • Separately fixed a second bug: the credit-pack Stripe price was recurring (turning pack buyers into $10/mo subscribers). Created a one-time price, repointed STRIPE_CREDIT_PACK_PRICE_ID (backend + client env), archived the old price. Client web/OTA rollout in progress.

🤖 Generated with Claude Code

The STRIPE_WEBHOOK_SECRET stored in Secret Manager had a trailing
newline, which made stripe.webhooks.constructEvent reject every live
event with a signature-verification error (400). No credits were
granted to any paying customer, silently.

Trim both STRIPE_WEBHOOK_SECRET and the stripe-signature header before
verification (mirrors validateAndNormalizeStripeSecretKey for the API
key). Add a regression test with a newline-suffixed secret and padded
signature, and document STRIPE_WEBHOOK_SECRET in .env.example as a
Secret-Manager value that must have no trailing whitespace.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 07be9a20-fddc-4510-9999-502c176e35ab

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes Stripe webhook signature verification failures caused by stray whitespace (notably trailing newlines) in STRIPE_WEBHOOK_SECRET and potentially padded stripe-signature headers, preventing dropped events and missed credit grants.

Changes:

  • Trim STRIPE_WEBHOOK_SECRET before calling stripe.webhooks.constructEvent.
  • Trim and validate the stripe-signature header before verification.
  • Add a regression test covering newline-suffixed secret and padded signature; document STRIPE_WEBHOOK_SECRET usage in functions/.env.example.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
functions/src/stripeWebhook.ts Trims webhook secret and signature header prior to Stripe event verification.
functions/src/stripeWebhook.test.ts Adds regression test asserting trimmed values are passed to constructEvent.
functions/.env.example Documents STRIPE_WEBHOOK_SECRET and warns against trailing whitespace/newlines.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Follow-up ticket for the next agent: end-to-end pack-purchase smoke test
once the front-end deploy lands, and investigation of the analytics gaps
(no GA4 purchase/conversion event; BigQuery export vs. Connections page).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@equationalapplications
equationalapplications merged commit d1c1f65 into staging Jul 20, 2026
3 checks passed
@equationalapplications
equationalapplications deleted the fix/stripe-webhook-secret-whitespace branch July 20, 2026 14:28
equationalapplications added a commit that referenced this pull request Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants