Session csrf_token versus LiveView csrf_token

I had some time to look into this more.

It turns out this was all a misunderstanding, caused by getting confused by how Plug.CSRFProtection handles CSRF tokens internally.

How Plug.CSRFProtection handles CSRF tokens internally

Plug.CSRFProtection has an internal concept of “masked” (long) and “unmasked” (short) CSRF token. The one you get when you call get_csrf_token/0 is the masked one, but the one it stores in the session (which you see if manually getting the session or looking at the mount call, or inspecting the cookie) is the unmasked one. However, these are the same and you can check that they match as ingmar already did above:

I guess the masking is something to do with preventing timing attacks.

LiveView Components add the CSRF token automatically

form will automatically add the CSRF token (which it gets from the process dictionary, which is populated from the session cookie, as described in the previous post) to the form if it contains an action parameter. A form generated by mix phx.gen.live doesn’t contain action by default, as it’s assumed the form will be submitted via LiveView, but if you add it, the CSRF token will be added. For example

<.form for={@form} action={~p"/example/path"}>...</.form>

This form will include the masked/long CSRF token in a _csrf_token field by default, due to the presence of the action param.

Additionally, while looking into this, I also found this post which confused me, because what it described is all unnecessary - maybe it was an issue on older versions:

Now the issue described in that article also works out of the box with a link like this:

<.link method="delete", href={~p"/example/path"}>Delete</.link>

This generates a link with the relevant CSRF token included automatically.


To go full circle, the only thing I’m not sure about, is what the purpose of this is, considering components make their own calls to Plug.CSRFProtection to get the csrf token, so there doesn’t seem to be a need to pass it back from the browser: