Is it always best to use push_navigate when updating user details in database?

I have a LiveView that allows a logged-in user to modify his settings (name, password, etc.). Each of the fields that allows modification is implemented as a dedicated Live Component with its own state. The Live Components are presented in a modal view from the parent component.

I pass the redirect path to the Live Component, which then performs the update actions (querying external API if applicable and updating the local database).

Since the Live Components are presented modally, I was using push_patch/2 to patch to the parent LiveView and using send() to pass the updated user to the parent’s handle_info/3 callback, which would then set socket.assigns.current_user of the LiveView to include the changes that were made.

My concern was that this could theoretically introduce a security hole since it would skip requires_authenticated_user via the mount callback. Or, at the very least that the database might diverge from what is displayed in the front-end.

So, I’ve replaced the call to push_patch/2 with one to push_navigate/2 on a successful user modification (I still use push_patch/2 on an unsuccessful one).

My question is whether this was necessary or whether it would be okay to stick with push_patch/2. Were my security concerns valid? Are there other considerations? What is the best practice here?

If I am reading this correctly as long as you aren’t accepting a user_id as a parameter you’re fine. You can’t push_patch to a live view that isn’t mounted, and end users can’t pass information to handle_info. To get the liveview up and running at all you have to pass the mount gate.

Agreed with @benwilson512. If the parent LiveView gets notified and passed a new user struct that comes straight from a successful database update, that should do the opposite unless maybe streams are involved somehow. Authentication only needs to happen on mount, it’s authorization that needs to happen on mount as well as ongoing handle_event as discussed in LiveView Security considerations.

Some other considerations that came to mind:

  • if your users are likely to have multiple LiveView clients/connections e.g. multiple tabs and/or devices, you might want to broadcast() the updated user instead

  • if you’re using Phoenix.Presence to show active users say in a chatroom, you might want to implement and incorporate the optional handle_metas/4 callback on your presence module as described in Using Elixir as a Presence Client

  • if it’s an authentication and/or authorization related change in particular e.g. password or roles/permissions, you might want to close all or all other LiveView connections and require re-authentication

1 Like