LiveView Security with phx.gen.auth

I’ve used mix phx.gen.auth to create an authentication system. Now the user session/reset password is part of the non-LiveView app while most authenticated points are “live”. The only exception is the UserSettings portion of the auth. I’d like these to be “live” as well.

The first thing I tried was moving the “update password” feature to live. So I made a LiveComponent to open a modal and, using phx-trigger-action, I can validate inside the LiveView component and then submit it to the UserSettingsController to handle clearing the session and re-logging in the user. Then it’ll kick me back to the live session.

This all works fine, but I can’t help wonder if there may be a security issue here.

  1. Is it safe to send the new password this way?

  2. When the form validates, it automatically clears the password fields. I then have to repopulate the values using socket.assigns before submitting over HTTP. Is there an issue with having the passwords in the assigns or manually set using the value attribute?

3 Likes

I think you might find this thread helpful.

I’m not totally following your question but your change_password_component.html.leex (or equivalent) might look something similar to this:

<%= f = form_for @password_changeset, Routes.person_settings_path(@socket, :update_password),
        id: "form-update-password",
        phx_change: "validate_password",
        phx_submit: "update_password",
        phx_trigger_action: @password_trigger_action,
        phx_target: @myself %>
  ...
  <%= hidden_input f, :action, name: "action", value: "update_password" %>
  <%= password_input f, :password, value: input_value(f, :password) %>
  ...
</form>

I’ve stripped out a lot, but the input_value/2 from Phoenix.HTML needs to be set on your password field.

And you use the update/2 callback for Phoenix.LiveComponent in your change_password_component.ex file (or equivalent):

  @impl true
  def update(assigns, socket) do
    if socket.assigns[:current_person] do
      {:ok, socket}
    else
      {:ok,
       socket
       |> assign(:current_person, assigns.current_person)
       |> assign(:password_changeset, Accounts.change_person_password(assigns.current_person))
       |> assign(:current_password, nil)
       |> assign(:password_trigger_action, false)
      }
    end
  end
  ...

You’d also have handle_event/3 callbacks for "validate_password" and "update_password", or whatever you’d like to call those actions.

I’m planning to add another Medium post on switching the settings page over to a Live View page as a continuation of my other two posts (which you can find in the aforementioned thread), and I will update @slouchpie’s thread accordingly.

Hope this helps :heart:

2 Likes

Thanks, that was very helpful. In the other thread, you mentioned how bytepack_archive also moved some stuff into LiveView and I was just looking at that archive. Great to know they’re doing the same things I was questioning in this thread.

1 Like