Callback
There are two callback functions reserved for use in the generated modules when we use the hmac security scheme of the OpenAPI Specification.
crypto_config/3, provides a way to define the crypto-related key information for the high level usage, it required to return aOasis.HMACToken.Cryptostruct (or nil).verify/3, an optional function to provide a way to custom the verification of the token, you may want to validate request datetime, HTTP body or other more rules to verify it.
Example
Here is an example to verify that HTTP request time does not exceed the current time by 1 minute.
defmodule Oasis.Gen.HMACAuth do
@behaviour Oasis.HMACToken
alias Oasis.HMACToken.Crypto
# in seconds
@max_diff 60
@impl true
def crypto_config(_conn, _opts, _credential) do
%Crypto{
credential: "...",
secret: "..."
}
end
@impl true
def verify(conn, token, opts) do
with {:ok, _} <- Oasis.HMACToken.verify(conn, token, opts),
{:ok, timestamp} <- conn |> get_header_date() |> parse_header_date() do
timestamp_now = DateTime.utc_now() |> DateTime.to_unix()
if abs(timestamp_now - timestamp) < @max_diff do
{:ok, timestamp}
else
{:error, "expired"}
end
end
end
defp get_header_date(conn) do
conn
|> Plug.Conn.get_req_header("x-oasis-date")
|> case do
[date] -> date
_ -> nil
end
end
defp parse_header_date(str) when is_binary(str) do
with {:ok, datetime, 0} <- DateTime.from_iso8601(str) do
{:ok, DateTime.to_unix(datetime)}
end
end
defp parse_header_date(_otherwise), do: {:error, "expired"}
end
Summary
Types
Structured verification error returned by verify/3.
String status code used in verify_error().
Functions
Sign HTTP requests according to settings.
Default implementation of the callback verify, only verify the signature.
Types
@type opts() :: Plug.opts()
@type verify_error() :: {:error, verify_error_status()}
Structured verification error returned by verify/3.
The second tuple element is a fixed string status code rather than an atom.
@type verify_error_status() :: String.t()
String status code used in verify_error().
Allowed values are:
"header_mismatch""invalid_credential""invalid_token""expired"
Elixir typespecs cannot enumerate string literals directly, so this remains
String.t() at the type level and the fixed set is documented here.
Callbacks
@callback crypto_config( conn :: Plug.Conn.t(), opts :: Keyword.t(), credential :: String.t() ) :: Oasis.HMACToken.Crypto.t() | nil
@callback verify(conn :: Plug.Conn.t(), token :: token(), opts :: opts()) :: {:ok, term()} | verify_error()
Functions
@spec sign( conn :: Plug.Conn.t(), signed_headers :: String.t(), secret :: String.t(), algorithm :: Oasis.Plug.HMACAuth.algorithm() ) :: String.t()
Sign HTTP requests according to settings.
@spec verify( conn :: Plug.Conn.t(), token :: token(), opts :: Oasis.Plug.HMACAuth.opts() ) :: {:ok, term()} | verify_error()
Default implementation of the callback verify, only verify the signature.
Error statuses are normalized to strings for Oasis's public callback contract.