Ueberauth fails to build when testing

Hello world,

So I am setting up a Phoenix server with authentication via Ueberauth & Auth0. When I run the server it boots up just fine (everything compiles). But, when I run mix test, one of my controllers fails to build. The failure looks like this:

Compiling 24 files (.ex)

== Compilation error in file lib/onward_web/controllers/auth_controller.ex ==
** (FunctionClauseError) no function clause matching in Keyword.pop/3

    The following arguments were given to Keyword.pop/3:

        # 1
        nil

        # 2
        :base_path

        # 3
        "/auth"

    Attempted function clauses (showing 1 out of 1):

        def pop(keywords, key, default) when is_list(keywords)

    (elixir) lib/keyword.ex:964: Keyword.pop/3
    lib/ueberauth.ex:177: Ueberauth.init/1
    (plug) lib/plug/builder.ex:302: Plug.Builder.init_module_plug/4
    (plug) lib/plug/builder.ex:286: anonymous fn/5 in Plug.Builder.compile/3
    (elixir) lib/enum.ex:1925: Enum."-reduce/3-lists^foldl/2-0-"/3
    (plug) lib/plug/builder.ex:284: Plug.Builder.compile/3
    (phoenix) expanding macro: Phoenix.Controller.Pipeline.__before_compile__/1
    lib/onward_web/controllers/auth_controller.ex:1: OnwardWeb.AuthController (module)

Seeing as the arguments given to the failing function include "auth", this suggests to me that the router.ex file may be the problem (as this is where the “auth” route is defined). Below, I’ll include the auth_controller.ex and the router.ex files.

Note: I realize that the code won’t run properly as is. I was in the middle of adding support for tokens when I discovered this build error.

router.ex

defmodule OnwardWeb.Router do
  use OnwardWeb, :router
  require Ueberauth

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  pipeline :auth do
    plug :add_token_to_conn
  end

  scope "/", OnwardWeb do
    pipe_through [:browser, :auth]

    get "/", PageController, :index
  end

  scope "/auth", OnwardWeb do
    pipe_through :browser

    get "/logout", AuthController, :logout
    get "/:provider", AuthController, :request
    get "/:provider/callback", AuthController, :callback
  end

  defp add_token_to_conn(conn, _params) do
    token = get_session(conn, :token)
    case token do
      nil ->
        conn
        |> redirect(to: "/auth/auth0")
        |> halt
      token ->
        conn
        |> assign(:token, token)
    end
  end
end

auth_controller.ex

defmodule OnwardWeb.AuthController do
  use OnwardWeb, :controller
  plug Ueberauth

  alias Onward.Accounts.User
  alias Onward.Repo
  alias Ueberauth.Auth


  def logout(conn, _params) do
    conn
    |> configure_session(drop: true)
    |> redirect(to: "/")
  end

  def callback(%{assigns: %{ueberauth_auth: auth}} = conn, _params) do
    {:ok, user} = get_or_create(auth)
    conn
    |> put_session(:current_user, user)
    |> redirect(to: "/")
  end

  defp get_or_create(%Auth{} = auth) do
    info = info_from(auth)
    case Repo.get_by(User, email: info.email) do
      nil -> %User{}
      user -> user
    end
    |> User.changeset(info)
    |> Repo.insert_or_update
  end

  defp info_from(%Auth{} = auth),
    do: %{
      first_name: first_name_from(auth),
      last_name: last_name_from(auth),
      phone: phone_from(auth),
      email: email_from(auth)
    }

  defp first_name_from(%Auth{info: %{first_name: first_name}}),
    do: first_name

  defp last_name_from(%Auth{info: %{last_name: last_name}}),
    do: last_name

  defp phone_from(%Auth{info: %{phone: phone}}),
    do: phone

  defp email_from(%Auth{info: %{email: email}}),
    do: email
end
1 Like

I figured out what was wrong. In the application config, if you don’t setup the Ueberauth config for your given environment (in my case, the “test” environment) then you get this cryptic compile error.

2 Likes