Thank you for your effort to help clearing things up.
So lets say that the purpose of CSRF tokens is to give me some confidence that the request comes from my browser app.
That’s exactly how I understand this technique so in this respect we are on the same page.
But what kind of request are we talking about?
a) mounting the liveview
b) liveview -> render form -> post stuff -> got request
I am assuming that I should use this token: get_connect_params |> Map.get("_csrf_token")
to validate mount/3
(option a), something along the lines of:
case token_from_connect_params do
^token_from_session -> :great_stuff
_csrf_attack -> :bad_news
end
Suppose the actual purpose is option b then I am misunderstanding all of this completely.
Probably someone can think of some obscure use case for option b.
To me that would be an edge case, so I would guess the purpose is option a.
so… how do I get rid of :bad_news
?
I did (finally) find a relation between the two csrf tokens:
Plug.CSRFProtection.dump_state() | "0Nt0DUzw_86ttI3jIcNFPV61"
x: mount/3 -> session -> "_csrf_token" | "0Nt0DUzw_86ttI3jIcNFPV61"
Plug.CSRFProtection.dump_state_from_session(a) | "0Nt0DUzw_86ttI3jIcNFPV61"
y: socket -> get_connect_params -> "_csrf_token" | "ZB4uAHB4KidmSmUrOQVbUgYSenMICUx0TPZ04-PP9rS_MLh8Oq45X_zE"
Plug.CSRFProtection.valid_state_and_csrf_token?(x, y) | true <-- got match!
So I can validate mounting the liveview:
@impl true
def mount(%{} = request_params, %{} = session, socket) do
case Map.get(session, "_csrf_token") do
nil ->
:ok = :secret_key_base
|> socket.endpoint.config
|> Plug.CSRFProtection.load_state(nil)
token = Plug.CSRFProtection.dump_state()
session = Map.put(session, "_csrf_token", token)
mount(request_params, session, socket)
session_state ->
connect_params = Phoenix.LiveView.get_connect_params(socket) || %{}
csrf_token = Map.get(connect_params, "_csrf_token")
loading? = is_nil(csrf_token)
valid_token? = Plug.CSRFProtection.valid_state_and_csrf_token?(
session_state, csrf_token
)
state = case {loading?, valid_token?} do
{true, false} -> :loading
{false, true} -> :complete
_csrf_attack -> :error
end
{:ok, assign(socket, mount: state)}
end
end
However, if this is correct, why is it not in the manual?
So probably it’s not correct.
And if it’s not correct, then what is the purpose of the csrf token?