Guardian authenticates a path that isn't found in its scope

I’m writing an api that needs to be authenticated, but a specific path (the create user path) doesn’t need to be authenticated.

  scope "/", AttoLinkWeb do
    pipe_through [:api]
    post "/", UserController, :create
  end

The rest of the end points are placed in another scope macro

  scope "/api", AttoLinkWeb do
    pipe_through [:api, :auth]
    get "/preview", PreviewController, :create
    resources "/user", UserController, except: [:new, :edit, :create]
    resources "/", ApiController, except: [:new, :edit]
  end

The authentication pipeline and api pipeline are as follows


  pipeline :api do
    plug :accepts, ["json"]
  end

  pipeline :auth do
    plug AttoLink.Auth.Pipeline

  end

This is the authentication pipeline.

defmodule AttoLink.Auth.Pipeline do
  use Guardian.Plug.Pipeline,
    otp_app: :atto_link,
    error_handler: AttoLink.Auth.ErrorHandler,
    module: AttoLink.Auth.Guardian

  plug Guardian.Plug.VerifySession, claims: %{"typ" => "access"}
  plug Guardian.Plug.VerifyHeader, claims: %{"typ" => "access"}
  plug Guardian.Plug.EnsureAuthenticated
  plug Guardian.Plug.LoadResource, allow_blank: true
end

As you can see, the api i’m building has two different end points in two different scopes, but everytime i run the user_controller_test it returns message: unauthenticated, which means all my tests aren’t passing.

defmodule AttoLinkWeb.UserControllerTest do
  use AttoLinkWeb.ConnCase

  alias AttoLink.Accounts
  alias AttoLink.Accounts.User

  @create_attrs %{
    email: "some email",
    password: "some password_hash"
  }
  @update_attrs %{
    email: "some updated email",
    password: "some updated password_hash"
  }
  @invalid_attrs %{email: nil, password: nil}

  def fixture(:user) do
    {:ok, user} = Accounts.create_user(@create_attrs)
    user
  end

  setup %{conn: conn} do
    {:ok, conn: put_req_header(conn, "accept", "application/json")}
  end

  describe "index" do
    test "lists all user", %{conn: conn} do
      conn = get(conn, Routes.user_path(conn, :index))
      assert json_response(conn, 200)["data"] == []
    end
  end

  describe "create user" do
    #fails with 401 error when it should succeed
    test "renders user when data is valid", %{conn: conn} do
      conn = post(conn, Routes.user_path(conn, :create), user: @create_attrs)
      assert %{"id" => id} = json_response(conn, 201)["data"]

      conn = get(conn, Routes.user_path(conn, :show, id))

      assert %{
               "id" => id,
               "email" => "some email"
             } = json_response(conn, 200)["data"]
    end

    test "renders errors when data is invalid", %{conn: conn} do
      #fails with 401 when it should fail with 422
      conn = post(conn, Routes.user_path(conn, :create), user: @invalid_attrs)
      assert json_response(conn, 422)["errors"] != %{}
    end
  end

  describe "update user" do
    setup [:create_user, :sign_in_user]

    test "renders user when data is valid", %{conn: conn, user: %User{id: id} = user} do
      conn = put(conn, Routes.user_path(conn, :update, user), user: @update_attrs)
      assert %{"id" => ^id} = json_response(conn, 200)["data"]

      conn = get(conn, Routes.user_path(conn, :show, id))

      assert %{
               "id" => id,
               "email" => "some updated email"
             } = json_response(conn, 200)["data"]
    end

    test "renders errors when data is invalid", %{conn: conn, user: user} do
      conn = put(conn, Routes.user_path(conn, :update, user), user: @invalid_attrs)
      assert json_response(conn, 422)["errors"] != %{}
    end
  end

  describe "delete user" do
    setup [:create_user, :sign_in_user]

    test "deletes chosen user", %{conn: conn, user: user} do
      conn = delete(conn, Routes.user_path(conn, :delete, user))
      assert response(conn, 204)

      assert_error_sent 404, fn ->
        get(conn, Routes.user_path(conn, :show, user))
      end
    end
  end

  defp create_user(_) do
    user = fixture(:user)
    {:ok, user: user}
  end

  defp sign_in_user(%{conn: conn, user: user}) do
    {:ok, token, _claims} = AttoLink.Auth.Guardian.encode_and_sign(user)
    conn = conn |> put_req_header("authorization", "bearer: " <> token)
    {:ok, user: user, conn: conn}
  end
end

I’ve checked just about everything. I’m currently using guardian 2.0.0. If you have any solutions please point me in the right direction.

Have you verified that Routes.user_path(conn, :show, id) generates the correct url corresponding with what you have in the router, as in / ? Every thing else seems OK to me at first sight.

Umm the problem was that after passing the first assert which was unauthenticated, i was making an unauthenticated request with the get(conn, Routes.user_path(conn, :show, id)). Had to bust out the debugger for that.

Can you mark the question as solved? That way nobody else will put time in trying to come up with an answer that was already found/given…

1 Like