Tutorial

Set session values from LiveView

liveview session

Basically, every web application has a need to store session values for the user visiting the page. At least with some sort of authentication, you store an authentication token or current user ID so you can retrieve the user for every request. There are also other use cases like preferences regarding language or dark mode. In a live view application, which mainly communicates over web sockets, you can't set session values directly. However, as you can see here, when I click the Set Session button and refresh the page, the value is still accessible through the user's browser session. So in this video, I will go through how you can easily add this in an elegant way.

Setting Up the StoreSession Controller

As mentioned, I can't set a session value directly from the live view. I need to create a controller that I can post to, which in turn can set a session value for the user. The controller supports both encrypted and non-encrypted params, though I strongly recommend using encryption in production:

defmodule TutorialWeb.StoreSessionController do
  use TutorialWeb, :controller

  def create(conn, %{"encrypted" => token}) do
    updated_conn =
      case decrypt(token) do
        {:ok, params} ->
          Enum.reduce(params, conn, fn {key, value}, acc_conn ->
            put_session(acc_conn, key, value)
          end)
        _ ->
          conn
      end

    send_resp(updated_conn, 200, "")
  end

  # Note: For development only. Use encryption in production
  def create(conn, params) do
    updated_conn = Enum.reduce(params, conn, fn {key, value}, acc_conn ->
      put_session(acc_conn, String.to_existing_atom(key), value)
    end)

    send_resp(updated_conn, 200, "")
  end

  defp decrypt(token) do
    Phoenix.Token.decrypt(TutorialWeb.Endpoint, "secret_key", token, max_age: 600)
  end
end

Note that for security reasons, we use String.to_existing_atom(key). We do that for security reasons, so this means that the atom needs to have been defined before. Also, for security, consider:

  1. Use a whitelist of allowed session keys
  2. Store the secret key in config
  3. Adjust the token max age based on your needs

Adding the Event Listener

Even though I added the controller, we can't post to it directly. Instead, we can dispatch a JavaScript event from inside the live view. So here in the app JavaScript file, I will add an event listener that listens for these events, takes the payload, and posts it to the new store session route:

window.addEventListener("phx:store-session", (event) => {
  const token = document.querySelector('meta[name="csrf-token"]').getAttribute('content')

  fetch('/store-session', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-CSRF-Token': token
    },
    body: JSON.stringify(event.detail)
  })
})

One thing to note here is that I grabbed the CSRF token from the meta tag in the DOM and use it as a header when posting. That is a way for Phoenix to verify that the post is legitimate.

Configuring a Route for Session Storage

Before I can post to the controller, I need to set up a route for it. Depending on your app and your security concerns, you can put this behind an authenticated pipeline:

scope "/", TutorialWeb do
  pipe_through :browser

  post "/store-session", StoreSessionController, :create
end

LiveView Event Trigger Example

The final piece of the puzzle is triggering the session update from LiveView. By emitting a custom event, we can communicate with our JavaScript hook to initiate the session storage process. Here’s an example of how this is accomplished in LiveView:

def handle_event("demo", _param, socket) do
  {
    :noreply,
    socket
    |> push_event("store-session", %{encrypted: encrypt(%{my_key: "My Value"})})
  }
end

defp encrypt(payload) do
  Phoenix.Token.encrypt(TutorialWeb.Endpoint, "secret_key", payload)
end

Conclusion

So now we have overcome one of the limitations in Phoenix LiveView regarding session management. By combining a small amount of JavaScript with a custom controller, we can securely set session values directly from LiveView. I hope this helps you in your application.

Related Tutorials

Published 25 Nov - 2022
Updated 29 Nov - 2022
Phoenix 1.7

Sortable lists with Phoenix LiveView and SortableJS

A very common user interface pattern on the web is to have sortable elements. In this tutorial I will go through how to accomplish sortable lists wi..

Published 31 May - 2023
Phoenix 1.7

CSV Import file upload with preview in LiveView

In this tutorial, I will go through how to upload and import a CSV file with Phoenix LiveView and, show how easy it is to preview the imports before..