View Source PhoenixApiToolkit.Security.HmacPlug (Phoenix API Toolkit v3.1.2)
Checks HMAC authentication. Expects a HMAC-<some_algorithm> of the request body to be present in the
"authorization" header. Supported algorithms are those supported by :crypto.mac/4
.
Relies on PhoenixApiToolkit.CacheBodyReader
being called by Plug.Parsers
.
To be considered a valid request by the plug, a request has to meet the following criteria:
- the request path must match the
"path"
stated in the request body - the request HTTP method must match the
"method"
stated in the request body - the request
"timestamp"
must not be older thanmax_age
If the token is invalid for any reason, PhoenixApiToolkit.Security.HmacVerificationError
is raised,
resulting in a 401 Unauthorized response.
configuration-options
Configuration options
hmac_secret
as a binary (mandatory): the secret used to create the HMAChash_algorithm
as an atom (optional, defaults to:sha256
) the hashing algorithm used to create the HMACmax_age
in seconds (optional, defaults to120
) the maximum age of the request before it is considered invalid
request-body-format-example
Request body format example
{
"path": "/api/v2/accounts",
"method": "POST",
"timestamp": 1321321545,
"contents": {
"key1": "value1",
"something": "else"
}
}
examples
Examples
use Plug.Test
alias PhoenixApiToolkit.Security.HmacPlug
import PhoenixApiToolkit.TestHelpers
import PhoenixApiToolkit.CacheBodyReader
@secret "supersecretkey"
def opts, do: HmacPlug.init(lazy_hmac_secret: fn -> @secret end)
def conn_for_hmac(method, path, raw_body) do
conn(method, path, raw_body |> Jason.decode!())
|> application_json()
|> put_raw_body(raw_body)
end
# a correctly signed request is passed through
iex> body = create_hmac_plug_body("/", "POST", %{hello: "world"})
iex> {:ok, _raw_body, conn} = conn_for_hmac(:post, "/", body) |> put_hmac(body, @secret) |> cache_and_read_body()
iex> conn = HmacPlug.call(conn, opts())
iex> conn.body_params["contents"]
%{"hello" => "world"}
# requests that are noncompliant result in a PhoenixApiToolkit.Security.HmacVerificationError
iex> body = create_hmac_plug_body("/", "PUT", %{hello: "world"})
iex> {:ok, _raw_body, conn} = conn_for_hmac(:post, "/", body) |> put_hmac(body, @secret) |> cache_and_read_body()
iex> HmacPlug.call(conn, opts())
** (PhoenixApiToolkit.Security.HmacVerificationError) HMAC invalid: method mismatch
iex> body = create_hmac_plug_body("/", "POST", %{hello: "world"}, 12345)
iex> {:ok, _raw_body, conn} = conn_for_hmac(:post, "/", body) |> put_hmac(body, @secret) |> cache_and_read_body()
iex> HmacPlug.call(conn, opts())
** (PhoenixApiToolkit.Security.HmacVerificationError) HMAC invalid: expired