PinStripe.ParsersWithRawBody (PinStripe v0.3.1)

View Source

A custom Plug.Parsers that caches the raw request body for webhook routes.

This plug conditionally caches the raw body only for webhook endpoints configured in your application. For all other routes, it behaves like standard Plug.Parsers.

The raw body is needed for webhook signature verification, as the signature is computed over the exact bytes received from Stripe.

Usage

In your Phoenix endpoint, replace Plug.Parsers with this module:

# Before:
plug Plug.Parsers,
  parsers: [:urlencoded, :multipart, :json],
  pass: ["*/*"],
  json_decoder: Phoenix.json_library()

# After:
plug PinStripe.ParsersWithRawBody,
  parsers: [:urlencoded, :multipart, :json],
  pass: ["*/*"],
  json_decoder: Phoenix.json_library()

The raw body will be available in conn.assigns.raw_body as a list of binary chunks for webhook routes.

Configuration

Configure webhook paths in your config/runtime.exs as a list:

config :pin_stripe,
  webhook_paths: ["/webhooks/stripe"]

You can configure multiple webhook endpoints:

config :pin_stripe,
  webhook_paths: ["/webhooks/stripe", "/webhooks/stripe_connect"]

If no configuration is provided, the default path ["/webhooks/stripe"] will be used.

Multiple Webhook Endpoints

To add additional webhook endpoints:

  1. Add the path to the :webhook_paths config (as shown above)

  2. Create a new controller that uses PinStripe.WebhookController:

    defmodule MyAppWeb.StripeConnectWebhookController do use PinStripe.WebhookController

    handle "account.updated", fn event ->

     # Handle Connect events
     :ok

    end end

  3. Add the route in your router:

    scope "/webhooks" do post "/stripe_connect", MyAppWeb.StripeConnectWebhookController, :create end

Summary

Functions

Custom body reader that caches the raw request body.

Functions

cache_raw_body(conn, opts)

Custom body reader that caches the raw request body.

This function is passed to Plug.Parsers via the :body_reader option. It reads the body and stores it in conn.assigns.raw_body as a list of chunks (prepended for efficiency).