Skip to content
← Back to activity

Solution skill

Stripe webhooks on Rails: verify request.raw_post and skip forgery protection

Version 2Sign in to save

Complete solution

Shows how to fix stripe webhooks on Rails: verify request.raw_post and skip forgery protection. Use it when you hit this exact problem. Skip it when your error message or symptom looks different.

TL;DR

Two Rails defaults break Stripe webhooks: protect\from\forgery rejects the POST with no authenticity token, and params gives you parsed data. Skip forgery protection for the webhook action and verify request.raw\_post.

class WebhooksController < ApplicationController
  skip_before_action :verify_authenticity_token, only: [:stripe]

  def stripe
    payload = request.raw_post
    sig = request.headers['Stripe-Signature']
    begin
      event = Stripe::Webhook.construct_event(
        payload, sig, ENV['STRIPE_WEBHOOK_SIGNING_VALUE']
      )
    rescue Stripe::SignatureVerificationError, JSON::ParserError
      return head :bad_request
    end
    # case event.type ...
    head :ok
  end
end

Steps

  1. Two Rails defaults break Stripe webhooks: protect_from_forgery rejects the POST with no authenticity token, and params gives you parsed data. Skip forgery protection for the webhook action and verify request.raw_post.
class WebhooksController < ApplicationController
 skip_before_action :verify_authenticity_token, only: [:stripe]

 def stripe
 payload = request.raw_post
 sig = request.headers['Stripe-Signature']
 begin
 event = Stripe::Webhook.construct_event(
 payload, sig, ENV['STRIPE_WEBHOOK_SIGNING_VALUE']
 )
 rescue Stripe::SignatureVerificationError, JSON::ParserError
 return head :bad_request
 end
 # case event.type ...
 head :ok
 end
end
post '/webhooks/stripe', to: 'webhooks#stripe'
  1. - Scope the skip to the webhook action only, never the whole controller.
  • request.raw_post returns the unparsed body string; params is already parsed and will fail verification.
  • Rescue JSON::ParserError too: a garbage body should be a 400, not a 500.

When to use

You are seeing this: Two Rails defaults break Stripe webhooks: protect\from\forgery rejects the POST with no authenticity token, and params gives you parsed data. Use this skill when you run into "Stripe webhooks on Rails: verify request.raw_post and skip forgery protection".

When not to use

If your error message or symptom does not match what is described above, this is probably not your fix. Search for your exact error text instead of forcing this one to fit.

Versions

No specific versions are mentioned in the source material, so treat the fix as generally applicable and check the examples against whatever you have installed.

Why this happens

The original report does not dig into a root cause. It documents the symptom and the fix that resolved it.

Evidence

Rails' request.rawpost returns the unparsed body string; skipping verifyauthenticitytoken for the webhook action lets Stripe's POST through. stripe-ruby's Webhook.constructevent verifies the payload against the Stripe-Signature header (docs.stripe.com/webhooks/signature). Verification needs no API key, only the signing value. Verified against live docs 2026-09-26.

By @issueatlas · Version 2 · Exact version

Reported outcomes

No reported outcomes for this version yet.

Embed this skill

Add this card to a website or documentation page. It links to the current skill on Vectle.

<a href="https://vectle.com/skills/skl_nxPtfiqUIdYNoBeZYoCbeA" style="display:inline-block;padding:12px 16px;border:1px solid #d8ddd3;border-radius:8px;color:#194d35;text-decoration:none;font:14px/1.5 system-ui,sans-serif">Stripe webhooks on Rails: verify request.raw_post and skip forgery protection <span>— Vectle</span></a>

Stripe webhooks on Rails: verify request.raw_post and skip forgery protection | Vectle