ueberauth / guardian_phoenix

A collection of helpers for when using Guardian with Phoenix
MIT License
45 stars 10 forks source link

LiveView & Guardian #6

Open romaluca opened 4 years ago

romaluca commented 4 years ago

Hi, in LiveView i tried to use import Guardian.Phoenix.Socket ... current_resource(socket)

But doesn't work. How can i get the current user without get again from db? Thanks

dbernheisel commented 4 years ago

I didn't try with this library, but I was able to load the resource from the session when mounting a liveview with plain Guardian. Hope this helps!

```elixir defmodule MyAppWeb.Live.AuthHelper do @moduledoc "Helpers to assist with loading the user from the session into the socket" @claims %{"typ" => "access"} @token_key "guardian_default_token" def load_user(%{@token_key => token}) do case Guardian.decode_and_verify(MyApp.Accounts.Guardian, token, @claims) do {:ok, claims} -> MyApp.Accounts.Guardian.resource_from_claims(claims) _ -> {:error, :not_authorized} end end def load_user(_), do: {:error, :not_authorized} end # and in a Live view def mount(_params, session, socket) do {:ok, user} = MyApp.Live.AuthHelper.load_user(session) socket = assign(socket, :current_user, user) # ... end ``` For comparison for a connection w/ Plug: ```elixir # router.ex pipeline :load_auth do plug Guardian.Plug.Pipeline, module: MyApp.Accounts.Guardian, error_handler: MyApp.AccountErrorHandler plug Guardian.Plug.VerifySession, claims: %{"typ" => "access"} plug Guardian.Plug.VerifyHeader, claims: %{"typ" => "access"} plug Guardian.Plug.LoadResource, allow_blank: true end # guardian.ex defmodule MyApp.Accounts.Guardian do @moduledoc "Convert JWT to and from user" use Guardian, otp_app: :my_app alias MyApp.Accounts def subject_for_token(user, _claims) do {:ok, to_string(user.id)} end def resource_from_claims(%{"sub" => id}) do case Accounts.find_user(id) do nil -> {:error, :not_found} user -> {:ok, user} end end end ```
mssobhan commented 4 years ago

I am planning to use this in LiveView. Can you assist a bit more. I want to build a small system using LiveView (for running a simple system related to the current COVID pandemic). In another portion of the same project for rest API I am already using guardian for user authentication based on Bearer Token.

Hanspagh commented 4 years ago

Hi @mssobhan. Did you try the above suggested solution?

mssobhan commented 4 years ago

Hi @mssobhan. Did you try the above suggested solution?

I will try it out and update you today. I missed this code sample (it was sandwiched). Btw, the login page url will be different, of will it be in the same url, with a signup / login fields, and then this code will be applied? Is it something like that.

Hanspagh commented 4 years ago

The login page will just put the token in the session or cookie or where tou have decided to put it, this should not affect the above

happysalada commented 4 years ago

for those looking for a quick solution

erikhu commented 3 years ago

i created a fork of this project and add Guardian.Phoenix.SocketLive, i hope it help https://github.com/erikhu/guardian_phoenix , only you need to get is the token from the session and use it same as Guardian.Phoenix.Socket, i am trying to wonder some more wonderful idea to resolve it

Hanspagh commented 3 years ago

Hi @erikhu, what is the reason for not just using the Guardian.Phoenix.Socket module to do the auth, as I recall liveview just uses a normal socket to communicate over, correct me if I am wrong but I don't see a need for a special liveview socket module.

erikhu commented 3 years ago

@Hanspagh the type of liveview socket is different to the websocket, so if you use Guardian.Phoenix.Socket.authenticate(socket, MyApp.Guardian, token) in liveview it raise exception when try to assign the values, you could check it. anyway i would like to found out a better solution to it

jamilbk commented 2 years ago

@Hanspagh Here's the specific error in case it helps anyone else. The issue is the guardian_phoenix is aliasing Phoenix.Socket while LiveViews use Phoenix.LiveView.Socket, so the pattern match for assign/3 fails.

I'm happy to attempt a PR if the authors think it's worth implementing.

** (exit) an exception was raised:
    ** (FunctionClauseError) no function clause matching in Phoenix.Socket.assign/3
        (phoenix 1.6.6) lib/phoenix/socket.ex:321: Phoenix.Socket.assign(#Phoenix.LiveView.Socket<assigns: %{__changed__: %{}, flash: %{}, live_action: :index}, endpoint: FzHttpWeb.Endpoint, id: "phx-Ftc0Q0t22biVJgCF", parent_pid: nil, root_pid: nil, router: FzHttpWeb.Router, transport_pid: nil, view: FzHttpWeb.DeviceLive.Unprivileged.Index, ...>, :guardian_default_token, "...")
sukidhar commented 2 years ago

for those looking for a quick solution

  • on liveview mount/3 the second parameter is a session. if user is authenticated using guardian, it includes a "guardian_default_token"
  • using Guardian.resource_from_token/1 will return {:ok, resource, claims}.
  • you can add a helper in your guardian implementation that would combine both steps into a resource_from_session if you want to make it shorter

thank you so much!!! I got stuck for 2 hours till I found this solution...