View Source Oasis.HMACToken behaviour (oasis v0.5.1)

callback

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 a Oasis.HMACToken.Crypto struct (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

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} <- Timex.parse(str, "%a, %d %b %Y %H:%M:%S GMT", :strftime),
         timestamp when is_integer(timestamp) <- Timex.to_unix(datetime) do
      {:ok, timestamp}
    end
  end

  defp parse_header_date(_otherwise), do: {:error, :expired}
end

Link to this section Summary

Functions

Sign HTTP requests according to settings.

Default implementation of the callback verify, only verify the signature.

Link to this section Types

@type opts() :: Plug.opts()
@type token() :: %{
  credential: String.t(),
  signed_headers: String.t(),
  signature: String.t()
}
@type verify_error() ::
  {:error, :header_mismatch}
  | {:error, :invalid_credential}
  | {:error, :invalid_token}
  | {:error, :expired}

Link to this section Callbacks

Link to this callback

crypto_config(conn, opts, credential)

View Source
@callback crypto_config(
  conn :: Plug.Conn.t(),
  opts :: Keyword.t(),
  credential :: String.t()
) :: Oasis.HMACToken.Crypto.t() | nil
Link to this callback

verify(conn, token, opts)

View Source (optional)
@callback verify(conn :: Plug.Conn.t(), token :: token(), opts :: opts()) ::
  {:ok, term()} | verify_error()

Link to this section Functions

Link to this function

sign(conn, signed_headers, secret, algorithm)

View Source
@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.

Link to this function

verify(conn, token, opts)

View Source
@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.