lib/authtoken_plug.ex

defmodule AuthToken.Plug do
  @moduledoc """
  Plugs for AuthToken

  ## Examples

      import AuthToken.Plug

      pipeline :auth do
        plug :verify_token
      end

      scope "/protected/route", MyApp do
        pipe_through :auth

        resources "/", DoNastyStuffController
      end
  """

  import Plug.Conn

  @doc """
  Checks authentication token from authorization header.

  If this fails, send 401 with message "error": "auth_fail" or "error": "timeout" as JSON
  """
  @spec verify_token(Plug.Conn.t, any) :: Plug.Conn.t
  def verify_token(conn, _options) do
    token_header = get_req_header(conn, "authorization") |> List.first

    crypto_token = if token_header, do: Regex.run(~r/(bearer\:? )?(.+)/, token_header) |> List.last

    case AuthToken.decrypt_token(crypto_token) do
      {:error} ->
        conn
        |> put_resp_content_type("application/json")
        |> send_resp(:unauthorized, "{\"error\": \"auth_fail\"}")
        |> halt
      {:ok, token} ->
        conn |> check_token_time(token)
    end
  end

  @spec check_token_time(Plug.Conn.t, map) :: Plug.Conn.t
  defp check_token_time(conn, token) do
    cond do
      AuthToken.is_timedout?(token) ->
        conn
        |> put_resp_content_type("application/json")
        |> send_resp(:unauthorized, "{\"error\": \"timeout\"}")
        |> halt
      AuthToken.needs_refresh?(token) ->
        conn
        |> put_resp_content_type("application/json")
        |> send_resp(:unauthorized, "{\"error\": \"needs_refresh\"}")
        |> halt
      true ->
        conn
    end
  end
end