maltoe
Passing assigns to LiveView initial render without putting them in the session
Hello
,
looking for advise on this issue we’re having with LiveView + authentication. We have solutions, only I fear we’re missing something simple and obvious.
Situation: We have an authentication service and an app with a LiveView UI. Incoming requests to the app have already been sent to the auth service before and have received some tokens describing the authentication state (think user id) in the form of custom x- headers.
We’d like to verify them on every request, including of course within our LiveViews (see Security model in the docs). For the normal HTTP request (the initial rendering), we rely on a plug to verify the token, whereas in the websocket-connected LiveView process we use get_connect_info in combination with a x_headers option on the socket. Both work great in terms of authentication. However, we’d also like to be able to pass information from the token to the socket assigns for rendering. This works for the connected?-way with get_connect_info because that happens within an on_mount, yet for the plug-based authentication we’re struggling to find a satisfactory solution.
- We know about
live_sessionand itssessionoption → That of course allows us to copy assigns from the conn in the initial render into the “LiveView session” which makes them show up in thesessionsparameter toon_mount. However, it also causes them to be written to the HTML in the form of an attribute on the LiveView element, and then be sent along the websocket connection when the LiveView registers. We don’t want this behaviour as we don’t want to (needlessly) expose the token information to the client. We also don’t need the “session” to be sent along on the websocket connection anymore (becauseget_connect_info), all we want is to pass some assigns from the conn (in the initial render request) to the fake “socket” (still in the initial render request) available inon_mount. There has to be a way, right? - Idea 1: It would be most amazing if only we could have
get_connect_infowork on the conn in the initial render… Then we wouldn’t have to pass anything and exclusively authenticate in theon_mount - Idea 2: What also would be great would be if someone knew a way to remove entries from the “LiveView session” before rendering the HTML, so could use the
sessionoption without exposing anything.
Idea 3, passing the data through the process dictionary of course works fine, but there has to be a different way to achieve this, right? Does anyone have a solution for this that feels “right” in current LiveView best practises?
Thanks a lot in advance!
Best,
malte
related posts / article:
Marked As Solved
wanton7
Maybe I didn’t understand your question after all, I thought it was about how to pass authorization information for LiveSocket. So if I now understood correctly your problem was in it’s simplicity, how to pass data from router to LiveView during initial request? There is an example how to do that here in LiveView docs Referencing parent assigns
controller
conn
|> assign(:current_user, user)
|> LiveView.Controller.live_render(MyLive, session: %{“user_id” => user.id})LiveView mount
def mount(_params, %{“user_id” => user_id}, socket) do
{:ok, assign_new(socket, :current_user, fn → Accounts.get_user!(user_id) end)}
end
There is also previous thread talking about this LiveView lifecycle hook with access to Conn? but the link provided there by José doesn’t work anymore, this is the correct link Security considerations of the LiveView model — Phoenix LiveView v0.17.5
Also Liked
maltoe
the assign_new magic does the trick! Genius! Thanks a lot. No idea how I missed this section in the docs so far…
It’s a bit confusing, don’t you think? If you inspect the socket.assigns before calling assign_new, they sure do not contain any assigns from the conn. Only after a call to assign_new they’ll be copied over to the socket.assigns… Odd, but great that it works ![]()
Thanks a lot!
maltoe
For others here: For the time being, I went with the process dictionary option. So essentially I have something like
# endpoint
socket "/live", Phoenix.LiveView.Socket, websocket: [connect_info: [:x_headers]]
# router
plug :remember_x_headers_for_live_view
defp remember_x_headers_for_live_view(conn, _opts) do
Process.put(:x_headers, my_get_x_headers_func(conn))
end
# on_mount
defp x_headers(socket) do
if connected?(socket) do
get_connect_info(socket).x_headers
else
Process.get(:x_headers)
end
end
Feels a bit clumsy, but it works ![]()
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








