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…