How to provide current logged in user into LiveView Form component?

Hi guys,

I have a question, so I’m wondering what is the best way to do this?

I’m using Phoenix gen command, for generating liveview components, context, etc. Scaffold is pretty solid, but I have one question.

I’m tweaking original Phoenix Auth, to support multiple profiles. And I’m currently using logged in user information, in order to submit “has many” relationship between user and profile.

In Index liveview module, I have this piece of code:

 def mount(_params, %{"user_token" => user_token}, socket) do
    profiles = Profiles.list_profiles_by_user_token(user_token)
    
    socket = socket
      |> stream(:profiles, profiles)
      |> assign(:current_user, Accounts.get_user_by_session_token(user_token))

    {:ok, socket}
  end

Here I’m assigning currently logged in user profiles, and current_user. In my index.html.heex, I’m passing current_user value into <.live_component> like so:

<.modal :if={@live_action in [:new, :edit]} id="profile-modal" show on_cancel={JS.patch(~p"/profiles")}>
  <.live_component
    module={TrialmarkWeb.ProfileLive.FormComponent}
    -----------------------------------------------------
    current_user={@current_user}
    -----------------------------------------------------
    id={@profile.id || :new}
    title={@page_title}
    action={@live_action}
    profile={@profile}
    patch={~p"/profiles"}
  />
</.modal>

And on form_component.ex I’m using current_user value to create new profile associted to currently logged in user, like so:

 defp save_profile(socket, :new, profile_params) do
    case Profiles.create_profile(profile_params, socket.assigns.current_user) do
      {:ok, profile} ->
        notify_parent({:saved, profile})

        {:noreply,
         socket
         |> put_flash(:info, "Profile created successfully")
         |> push_patch(to: socket.assigns.patch)}

      {:error, %Ecto.Changeset{} = changeset} ->
        {:noreply, assign_form(socket, changeset)}
    end
  end

Long story short, my question is there a better way to do this, because providing value from heex file, can be mutated, and security would be an issue. For example someone can enter some other user profile, and submit it to his account.

What is best way to handle this stuff correctly?

Your example also just shows an example of creating a profile which wouldn’t be a security issue. For update, you just need to ensure the user owns the profile. This can be done in a variety of ways. I like to keep it in the domain layer and I like to pass the user as the first argument:

Profiles.update_profile(current_user, profile, profile_params)

Then your code can look something like this:

def update_profile(%User{id: user_id}, profile{user_id: user_id}, params) do
  # ...
end

This will raise if the two user_ids don’t match.

You also look at authorization libraries like Let Me or Janus.

Also, be careful of lines like this if you are using integer id:

id={@profile.id || :new}

LiveView gives you a warning if you use an integer as a component id (at least it used to!)