Phoenix_live_view: Token verification error with nested data.

Created on 13 Apr 2019  路  7Comments  路  Source: phoenixframework/phoenix_live_view

Environment

  • Elixir version (elixir -v): 1.8.1
  • Phoenix version (mix deps): 1.4.3
  • NodeJS version (node -v): 10.15.3
  • NPM version (npm -v): 6.4.1
  • Operating system: macOS Mojave 10.14.4

Actual behavior

When using associated schemas with live view the token verification fails if the session includes a changeset that was created with cast_assoc. Leaving out cast_assoc gets rid of the error but doesn't give the correct functionality.

[error] GenServer #PID<0.469.0> terminating
** (ArgumentError) cannot deserialize #Function<15.34706895/2 in Ecto.Changeset.on_cast_default/2>, the term is not safe for deserialization
    (plug_crypto) lib/plug/crypto.ex:59: Plug.Crypto.safe_terms/1
    (plug_crypto) lib/plug/crypto.ex:45: anonymous fn/3 in Plug.Crypto.safe_terms/1
    (stdlib) maps.erl:257: :maps.fold_1/3
    (plug_crypto) lib/plug/crypto.ex:78: Plug.Crypto.safe_tuple/2
    (plug_crypto) lib/plug/crypto.ex:45: anonymous fn/3 in Plug.Crypto.safe_terms/1
    (stdlib) maps.erl:257: :maps.fold_1/3
    (plug_crypto) lib/plug/crypto.ex:45: anonymous fn/3 in Plug.Crypto.safe_terms/1
    (stdlib) maps.erl:257: :maps.fold_1/3
    (plug_crypto) lib/plug/crypto.ex:45: anonymous fn/3 in Plug.Crypto.safe_terms/1
    (stdlib) maps.erl:257: :maps.fold_1/3
    (plug_crypto) lib/plug/crypto.ex:45: anonymous fn/3 in Plug.Crypto.safe_terms/1
    (stdlib) maps.erl:257: :maps.fold_1/3
    (plug_crypto) lib/plug/crypto.ex:45: anonymous fn/3 in Plug.Crypto.safe_terms/1
    (stdlib) maps.erl:257: :maps.fold_1/3
    (plug_crypto) lib/plug/crypto.ex:30: Plug.Crypto.safe_binary_to_term/2
    (phoenix) lib/phoenix/token.ex:177: Phoenix.Token.verify/4
    (phoenix_live_view) lib/phoenix_live_view/view.ex:155: Phoenix.LiveView.View.verify_token/2
    (phoenix_live_view) lib/phoenix_live_view/view.ex:146: Phoenix.LiveView.View.verify_session/3
    (phoenix_live_view) lib/phoenix_live_view/channel.ex:221: Phoenix.LiveView.Channel.mount/1
    (stdlib) gen_server.erl:637: :gen_server.try_dispatch/4
Last message: {:mount, Phoenix.LiveView.Channel}

I've created a simple application that reproduces the error here https://github.com/adamvaughan/testapp. Create/migrate the database, boot the server and visit the root path and you should see the error immediately.

Expected behavior

Token verification works without raising an error.

Most helpful comment

It depends on what you are storing in your session. It seems you are trying to store the whole Plug.Conn. You should only store integer, strings, and so on.

All 7 comments

So the issue is that you are trying to serialize data that cannot be serialized (i.e. it contains functions). You are supposed to put in the session the information necessary to retrieve the data, not the data itself. For example, instead of putting the user struct from Ecto in the session, put the user id and query it when live view starts.

I'm getting a similar issue with #Function<0.76412652/1 in Plug.CSRFProtection.call/2>. What could be the issue there?

It depends on what you are storing in your session. It seems you are trying to store the whole Plug.Conn. You should only store integer, strings, and so on.

Thanks for the clarification @josevalim! Switching to storing integers in the session and assigning other objects I wanted to have kept in state to the socket resolved this issue for me.

I would like to use route helpers in my LiveView template, but I can't assign the conn to the socket without getting the same error as above. I think am misssing something...

`  def mount(%{conn: conn, ranking: ranking}, socket) do
    weights = get_session_weights(ranking)
    fset = ranking.filter
    results = Rankings.get_ranked_results(fset, weights)
    openResults = set_open_results(results)
    socket = 
      socket
      #|> assign(conn: conn)   # Uncommenting this line will cause error
      |> assign(ranking: ranking)
      |> assign(fset: fset)
      |> assign(results: results)
      |> assign(score_weights: weights)
      |> assign(openFilters: MapSet.new([:stroke]))
      |> assign(openResults: openResults)
      |> assign(openScoreWeights: false)
    {:ok, socket}
  end`

@jamilabreu Have you tried build the route path using the socket instead? I believe it should work 馃

Routes.user_path(socket, :index)

Yes, socket works fine. Thank you.

Was this page helpful?
0 / 5 - 0 ratings