# `Twilio.Webhook`

Checks that a webhook request really comes from Twilio.

Twilio signs every request it sends to your app (incoming messages and
calls, status callbacks) with your auth token, in the `X-Twilio-Signature`
header. Check it before acting on the request:

    # A Phoenix controller
    def incoming_sms(conn, params) do
      signature = conn |> get_req_header("x-twilio-signature") |> List.first()

      if Twilio.Webhook.valid?(current_url(conn), params, signature) do
        # ...
      else
        send_resp(conn, 403, "")
      end
    end

The URL must be the one Twilio requested, query string included. Behind a
proxy or load balancer that is the public URL (`https://example.com/sms`),
not the one your app sees (`http://10.0.0.5:4000/sms`); build it from your
configured host if they differ.

Requests with a JSON body (some newer Twilio products) are signed over the
URL alone, with the body's SHA-256 in a `bodySHA256` query parameter: pass
the raw body, as a binary, instead of the params.

Webhooks signed with a SharedKey instead of the auth token say so in an
`X-Twilio-Webhooks-Signature-Settings` header; pass it as `:settings` and
the SharedKey secret as `:auth_token`.

Same rules as Twilio's official SDKs: parameters sorted by name, then value,
duplicates removed; the URL tried with and without its default port, since
Twilio signs either; signatures compared in constant time.

# `signature`

```elixir
@spec signature(String.t(), map() | keyword() | [{String.t(), term()}], keyword()) ::
  String.t()
```

The signature Twilio would send for a request to `url` with `params`:
useful in your tests, to sign the requests you send to your own webhook.

Takes the `:auth_token` and `:algorithm` options of `valid?/4`.

# `valid?`

```elixir
@spec valid?(
  String.t(),
  map() | keyword() | [{String.t(), term()}] | binary(),
  String.t() | nil,
  keyword()
) :: boolean()
```

Whether `signature` (the `X-Twilio-Signature` header) is Twilio's signature
of a request to `url` with `params`.

`params` is the form body as a map, keyword list or list of pairs (repeated
names allowed), or the raw body as a binary for JSON requests.

Options:

  * `:auth_token`: the secret it was signed with. Default:
    `config :twilio, auth_token: ...`, then the `TWILIO_AUTH_TOKEN`
    environment variable
  * `:settings`: the `X-Twilio-Webhooks-Signature-Settings` header, when
    the request has one
  * `:algorithm`: `:hmac_sha1` (the default) or `:hmac_sha256`, instead of
    reading it from `:settings`

---

*Consult [api-reference.md](api-reference.md) for complete listing*
