Tutorial
Phoenix LiveView and Invalid CSRF token
This post was updated 01 May - 2020
One issue that is common to run into is a CSRF error when posting some sort of form rendered with LiveView. The issue is that a LiveView component is mounted twice. First time when the component is rendered by the initial request. Then it has the correct CSRF token. Next time, when it connect to the socket, it get the wrong CSRF token. Or at least wrong in the sense that it doesn't match the one in the page header.
STEP 1
So, to fix this, you need to setup so that the LiveView connection so it uses the same session options. Open endpoint.ex
and change to:
@session_options [
store: :cookie,
key: "_tutorial_key",
signing_salt: "4qBWyMiY"
]
socket "/live", Phoenix.Live.View.Socket, websocket: [connect_info: [session: @session_options]]
...
plug Plug.Session, @session_options
Now that I have hooked up my session to the LiveView socket connection, I can create a plug that assigns the correct CSRF-token to a session cookie on every page request. I need to create a plug with the content:
defmodule TutorialWeb.GenerateCSRF do
import Plug.Conn, only: [put_session: 3]
def init(_opts), do: nil
def call(conn, _opts), do: put_session(conn, :csrf_token, Phoenix.Controller.get_csrf_token())
end
<small>([Thanks for the tip](https://github.com/phoenixframework/phoenix_live_view/issues/111#issuecomment-547251854))</small>
And mount that plug in the router:
pipeline :browser do
...
plug :put_secure_browser_headers
plug TutorialWeb.GenerateCSRF
end
Then, in my LiveView component productlistlive.ex
, I can extract it from the session argument like:
def mount(%{"csrf_token" => csrf_token} = _session, socket) do
assigns = [
conn: socket,
csrf_token: csrf_token
]
{:ok, assign(socket, assigns)}
end
And lastly, in my template, I can not use the csrf token:
<%= link "Delete", to: Routes.product_path(@conn, :delete, product), csrf_token: @csrf_token, method: :delete, data: [confirm: "Are you sure?"] %>
SUCCESS
Now you should be able to delete a product: