I have a modal form_component (generated by phx.gen.live). The liveview that kicks off the form_component is available to all users. But I want that form_component to require authentication via phx.gen.auth functionality. The problem is that the form_component doesn’t have a route that I can put under pipe_through [:browser, :require_authenticated_user]
Use Case is very similar to Pinterest: User is searching resources that anyone can view. They click on a link to “Save” the resource to a personal library of resources. User can have multiple libraries. Once they click “Save”, I want the user to be presented with a form_component that just asks them to select what library they want to save the resource to. But that requires authentication for only the form_component not the parent Liveview.
Possible Solution: I use a handle_event for “Save” to check for authentication and force user to authenticate if not logged in. Once authenticated, I kick off the form_component. Is that the best way to do this? Can I force authentication from inside the LiveView? I normally just doing it via the routes.
How do I get the user back to the modal form once authenticated? If I set the “socket.assigns.return_to” the modal path, won’t that socket get lost/cleared once the user is routed to the login form?
Sorry … I’m still new at all of this stuff. What is a whitelist? Do you mean that the return liveview must be in the “authenticated” section of routes? Unfortunately, I want them to return to the list of resources that must be in the “unauthenticated” route section because it is originally available to view by any user.
I have not been implementing any whitelists for the users. I have just been using router.ex to enforce authentication on the liveviews that require an authenticated user. Am I supposed to also be implementing whitelists?
I believe I ran into exactly this lately, juggling Phx.gen.auth and liveview. Phx.gen.auth generates code that adds user_token to the session info (see UserAuth.log_in_user/3 - the line put_session(:user_token, token)). This is a cookie that is set on the client and returned with each request.
But in order to access session info inside liveview socket assigns, you need to extract the data from the session and assign it in a LiveView’s mount.
I’ll try to provide a very minimal code sample:
defmodule MyAppWeb.RoomLive.Index do
use MyAppWeb, :live_view
def mount(_params, session, socket) do
socket = assign_user(session, socket)
{:ok, %User{} = user} <- get_current_user(socket)
#...
end
defp assign_user(%{"user_token" => user_token}, socket) do
Phoenix.LiveView.assign_new(socket, :current_user, fn ->
Accounts.get_user_by_session_token(user_token)
end)
end
defp assign_user(_session, socket) do
socket
end
defp get_current_user(socket) do
case Map.get(socket.assigns, :current_user) do
nil -> {:error, :not_authenticated}
user -> {:ok, user}
end
end
end
You need to do this in a LiveView and pass it down to the respective LiveComponent.
Apologies if I’m misreading your use-case, please let me know if so.
Ahh… hadn’t thought about someone trying to redirect users to porn site. Definitely don’t want that.
I’m running into two issues:
All of the routes related to user authentication (user_registration_path, user_session_path, sketcher_confirmation_path, etc) require a conn as a parameter. But I’m sitting in a liveview and just have a session and a socket.
Where do I put the whitelist return code that you suggested? Do I put that in the log_in_user(conn, user, params) function within the user_auth.ex controller? I see that the log_in_user function is grabbing the :user_return_to set inside the session. What you’re suggesting is that I unpack the params and reset the return_to path (after checking the whitelist). Is that correct?
Thanks for your post. I’m trying to do something slightly different. I’ve got code that will allow me to access the user within liveviews that are under authenticated paths. But my use case requires a liveview that can’t require authentication, but I want it to kick off a form modal that does require authentication. Unfortunately, form modals don’t have paths that get listed in routers.ex. So I’ve got to redirect to a user authentication path for authentication only when the user clicks “Save” … but I don’t have a conn.