How to read request body multiple times during request handling?

I used something like this recently (though not for stripe):

though halting in the plug somehow crashed my ngrok tunnel on my dev box - so ended up json decoding and putting a :verified assign on the conn and then passing it to a controller… kinda prefer having things in the controller anyways…

  def some_callback(%{assigns: %{verified: false}} = conn, _params) do
    send_resp(conn, 401, "")
  end

  def some_callback(%{assigns: %{verified: true, json: json}} = conn, params) do
    ..
  end

in the plug:

  defp verify_signature(conn, opts) do

    with [request_signature | _] <- get_req_header(conn, opts[:header]),
         secret when not is_nil(secret) <- opts[:secret],
         {:ok, body, new_conn} <- Plug.Conn.read_body(conn),
         signature =
           :crypto.hmac(
             :sha256,
             secret,
             body
           )
           |> Base.encode16(case: :lower),
         true <- Plug.Crypto.secure_compare(signature, request_signature) do
      # handle_webhook(conn, body)
      json = Poison.decode!(body)

      new_conn = assign(new_conn, :verified, true)
      new_conn = assign(new_conn, :json, json)
    else
      nil ->
        Logger.error(fn -> "Webhook secret is not set" end)
        conn = assign(conn, :verified, false)

      false ->
        Logger.error(fn -> "Received webhook with invalid signature" end)
        conn = assign(conn, :verified, false)

      _ ->
        conn = assign(conn, :verified, false)
    end
  end

let me know if you have any questions…

1 Like