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