How do I pass the correct CSRF token from a LiveView to a normal route?

I have a LiveView that lists Students at /students. I also have a resources "/students" that handles all the rest of my CRUD operations for students. When I try to DELETE to /students/:id using the link on the page, I’m getting an invalid CSRF token error:

[debug] ** (Plug.CSRFProtection.InvalidCSRFTokenError) invalid CSRF (Cross Site Request Forgery) token, make sure all requests include a valid '_csrf_token' param or 'x-csrf-token' header

My delete button looks like this:

<span><%= link "Delete", to: Routes.student_path(@socket, :delete, student), method: :delete, data: [confirm: "Are you sure?"] %></span>

How can I fix this?


If you are using a form to do the delete then you can add the CSRF token as a hidden field something like this.

# In a controller etc., you can use an assign and add the token
def index(conn, _) do
    render conn, "index.html", token: get_csrf_token()
# In a view add the token as a hidden field using the assign
  <input type="hidden" value="<%= @token %>" name="_csrf_token"/>

# Or call the get_csrf_token() function directly in the template
<form ...
  <input type="hidden" value="<%= Phoenix.Controller.get_csrf_token() %>" name="_csrf_token"/>

You can find it in the Phoenix docs here:


Thanks for the info, but there already seems to be a CSRF token on the button (as the data-csrf attribute), it just seems to be incorrect.

Ahh… I see. This is probably a good question for @chrismccord or @josevalim or someone who’s crossed this bridge before :slight_smile:

Sorry I wasn’t much help to you.


I fixed this by adding a _csrf_token parameter to the data list. I’m not sure why data-csrf works for regular requests and not requests coming from a LiveView, however.

1 Like

Hmm, it seems that I was mistaken. I had made a typo and added _csrf_token outside of the data list. This caused some bug with LiveView, which caused that attribute to not be updated when LiveView picked up from where the GET request left off. That meant that I had a dangling -csrf-token attribute which was used instead of the data-csrf attribute (which was updated via LiveView to some new CSRF token – I checked using the inspect tool that these attributes were indeed different).

Basically what this means is, LiveView is updating the CSRF token to something that is invalid. An explanation from @chrismccord or @josevalim would be appreciated here.

There already seems to be a bug report about this: