 
   Basic Authentication is specified in RFC 7617 (which obsoletes RFC 2617).
 
+  ## Fixed credentials
+
+      iex> request(:GET, "/")
+      ...> |> set_credentials("Aladdin", "open sesame")
+      ...> |> authenticate("Aladdin", "open sesame")
+      {:ok, "Aladdin"}
+
+      iex> request(:GET, "/")
+      ...> |> set_credentials("Aladdin", "open sesame")
+      ...> |> authenticate("Jafar", "open sesame")
+      {:error, :invalid_access_credentials}
+
+      # with {:ok, {user_id, password}} <- Raxx.BasicAuth.get_credentials(request) do
+      #   # check a users credentials
+      #   {:ok, user}
+      # end
+
   ## Examples
-  # Authenticate is Authenticated
+
+      iex> request(:GET, "/")
+      ...> |> set_credentials("Aladdin", "open sesame")
+      ...> |> get_credentials()
+      {:ok, {"Aladdin", "open sesame"}}
 
   ## NOTE
 
   The Basic authentication scheme is not a secure method of user authentication
   https://tools.ietf.org/html/rfc7617#section-4
 
-
+  This module will be extracted to a separate project before the release of raxx 1.0
   """
 
-  defmacro __using__(_opts) do
-    quote do
-      def authenticate(request) do
-        case get_credential(request) do
-          {user_id, password} ->
-            verify_credentials(user_id, password)
-          {:error, reason} ->
-            {:error, reason}
-        end
-      end
-# TODO define your own verify_credentials -> user
-    end
-  end
+  import Raxx
 
   @authentication_header "authorization"
   @default_realm "Site"
   @default_charset "UTF-8"
 
-  def set_authentication(request, user_id, password) do
+  @doc """
+  Add a users credentials to a request to authenticate it.
+
+  NOTE:
+  1. The user-id and password MUST NOT contain any control characters
+  2. The user-id must not contain a `:`
+
+  ## Examples
+
+      iex> request(:GET, "/")
+      ...> |> set_credentials("Aladdin", "open sesame")
+      ...> |> get_header("authorization")
+      "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
+  """
+  def set_credentials(request, user_id, password) do
     request
     |> set_header(@authentication_header, authentication_header(user_id, password))
   end
 
-  # TODO expose credentials function
-  def authenticate(request) do
-    # Raxx does not need to include OK
-    # ~>> fetch_authentication_header
-    case Raxx.get_header(request, @authentication_header) do
+  @doc """
+  Extract credentials submitted using the Basic authentication scheme.
+
+  If credentials we not provided or are malformed an error is returned
+  """
+  def get_credentials(request) do
+    case get_header(request, @authentication_header) do
       nil ->
         {:error, :not_authorization_header}
+
       authorization ->
         case String.split(authorization, " ", parts: 2) do
           ["Basic", encoded] ->
             case Base.decode64(encoded) do
               {:ok, user_pass} ->
-                case String.split(authorization, " ", parts: 2) do
+                case String.split(user_pass, ":", parts: 2) do
                   [user_id, password] ->
-                    :ok
+                    secure_compare(user_id, password)
+                    {:ok, {user_id, password}}
+
                   _ ->
                     {:error, :invalid_user_pass}
                 end
+
               :error ->
                 {:error, :unable_to_decode_user_pass}
             end
-          [unknown, _] ->
+
+          [_unknown, _] ->
             {:error, :unknown_authentication_method}
+
           _ ->
             {:error, :invalid_authentication_header}
         end
+    end
+  end
+
+  @doc """
+  Authenticate a request against fixed credentials.
+  """
+  def authenticate(request, access_user_id, access_password) do
+    with {:ok, {user_id, password}} <- get_credentials(request) do
+      if secure_compare(user_id, access_user_id) && secure_compare(password, access_password) do
+        {:ok, access_user_id}
+      else
+        {:error, :invalid_access_credentials}
+      end
     end
   end
 

    |> set_body("401 Unauthorized")
  end

  @doc """

  ## Examples

      iex> authentication_header("Aladdin", "open sesame")
      Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
  """
  def authentication_header(user_id, password) do
    "Basic " <> Base.encode64(user_pass(user_id, password))
  end


  def challenge_header(realm, nil) do
    "Basic realm=\"#{realm}\""
  end

  def challenge_header(realm, charset) do
    "Basic realm=\"#{realm}\", charset=\"#{charset}\""
  end

  defp user_pass(user_id, password) do
    :ok =
      case :binary.match(user_id, [":"]) do
        {_, _} ->
          raise "a user-id containing a colon character is invalid"

        :nomatch ->
          :ok
      end

    user_id <> ":" <> password
  end

  @doc """
  Compares the two binaries in constant-time to avoid timing attacks.
  See: http://codahale.com/a-lesson-in-timing-attacks/
  """
  def secure_compare(left, right) do
    if byte_size(left) == byte_size(right) do
      secure_compare(left, right, 0) == 0
    else
      false
    end
  end

  def secure_compare(<<x, left::binary>>, <<y, right::binary>>, acc) do
    import Bitwise
    xorred = x ^^^ y
    secure_compare(left, right, acc ||| xorred)
  end

  def secure_compare(<<>>, <<>>, acc) do
    acc
  end
end
