A custom Plug.Parsers body reader that caches the raw request body in
conn.assigns[:raw_body], so ExLine.Webhook.Plug can verify the LINE
signature after the JSON parser has consumed the stream.
Why you need this
LINE signs the exact bytes of the request body, and verifying the signature
means re-hashing those same bytes. You cannot use the parsed payload instead,
because JSON parsing is a one-way door: once Plug.Parsers turns the body into a
map, encoding that map back to JSON can reorder keys and change whitespace, so it
is no longer byte-for-byte identical to what LINE sent — and the signature won't
match.
On top of that, Plug.Parsers consumes the body stream as it parses, so by the
time your controller runs the original bytes are gone. This reader sits inside the
parser: it reads the body, stashes an untouched copy in conn.assigns[:raw_body],
and hands the same bytes on to the parser. JSON parsing still works as usual, and
the original bytes survive for signature verification.
Wire it into your endpoint's Plug.Parsers:
plug Plug.Parsers,
parsers: [:json],
body_reader: {ExLine.Webhook.BodyReader, :read_body, []},
json_decoder: JasonRef: https://hexdocs.pm/plug/Plug.Parsers.html#module-custom-body-reader
Summary
Functions
@spec read_body( Plug.Conn.t(), keyword() ) :: {:ok, binary(), Plug.Conn.t()}