Guardian session disappears

authentication
phoenix
#1

I am using Guardian Plug to authenticate via a REST API with JWT tokens. I would like to use the same site to login via the web and store a session with a cookie. I do this with the same pipeline as the one that issues jwt json. I’ve also tried implementing this with a completely different Guardian pipeline, but still seeing the same problem … so I think I’m missing something.

login_controller.ex:

    case Authenticator.get_user_for_email_or_name_password(email, password) do
      nil ->
        conn
        |> put_flash(:error, "Invalid credentials!")
        |> render("new.html")
      user ->
        conn
        |> GuardianImpl.Plug.sign_in(user)
        |> assign(:current_user, user)
        |> put_user_token(user)
        |> render("home.html")

This following chunk momentarily reports a valid current_resource(), but the moment I try to access an authenticated route /admin/notification/send, the Guardian ErrorHandler fires and returns 401(unauthorized because unauthenticated). I know for sure sign_out() is not being called … so what could be wrong?

      def user_logged_in?(conn) do
        GuardianImpl.Plug.current_resource(conn)
        !is_nil(GuardianImpl.Plug.current_resource(conn))
      end

router:

  # ---- Pipelines ----
  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
    plug :put_layout, {FaithfulWordApi.LayoutView, :app}
    plug(GuardianImpl.Pipeline)
  end

  pipeline :authentication_required do
    plug Guardian.Plug.EnsureAuthenticated
  end

  scope "/", FaithfulWordApi do
    pipe_through [:browser, :authentication_required]
    scope "/admin" do
      get "/upload", UploadController, :index
      get "/notification/send", PushMessageController, :index
    end
  end

#2

        conn
        |> GuardianImpl.Plug.sign_in(user)
        |> assign(:current_user, user)
        |> put_user_token(user)
        |> render("home.html")

Is this… correct? I have no idea how your Guardian Plug is implemented but IIRC guardian have it’s own function to create jwt tokens either :refresh or :claim. And iirc it would write the user cookie with the jwt created so I’m not entirely sure about this line |> assign(:current_user, user) |> put_user_token(user) or even what the logic behind it? Maybe I’m wrong…

#3

Sure I’ll look into that, tinker with it. I might just write my own Plug for web login session auth specifically. I think something with my guardian config is wrong, but I’m not sure.

One thing I forgot to mention: this is an umbrella app and the guardian config is in an app that is NOT running Phoenix. I will try adding a guardian config to the app running Phoenix and use an entirely new namespace to refer to the Guardian Plug. If that doesn’t work, I will try the non-Guardian Plug idea.

#4

OK so I managed to have Guardian save the session for web login. The issue was that I was using a Guardian pipeline in my router.ex configured in a separate umbrella app, which was configured to return JSON Web Token exclusively to ALSO manage sign_in() and sign_out() via a session. It just didn’t work.

In the app that contains phoenix, the solution was to configure in my config/config.exs another instance of Guardian which would manage a separate pipeline and plug under the app which shared the app namespace with phoenix. Both these Guardian pipelines seem to co-exist OK in the same router.ex file. Probably easier to show than write this out… but it works.