f0rest8

f0rest8

Invalid csrf error on phoenix 1.6.7 in (Plug.CSRFProtection.InvalidCSRFTokenError)

In development I noticed that when I update to the latest version of Phoenix (1.6.7), I now receive an invalid csrf error when attempting to login.

Deps Versions that work

  • phoenix 1.6.6
  • plug 1.13.4 / 1.13.6
  • phoenix_live_view 0.17.7 / 0.17.9
  • phoenix_pubsub 2.1.0 / 2.1.1

Error on phoenix 1.6.7

  * The session cookie is being sent and session is loaded
  * The request include a valid '_csrf_token' param or 'x-csrf-token' header
    (plug 1.13.6) lib/plug/csrf_protection.ex:316: Plug.CSRFProtection.call/2
    (metamorphic_web 0.1.0) MetamorphicWeb.Router.browser/2
    (metamorphic_web 0.1.0) lib/metamorphic_web/router.ex:1: MetamorphicWeb.Router.__pipe_through9__/1
    (phoenix 1.6.7) lib/phoenix/router.ex:347: Phoenix.Router.__call__/2
    (metamorphic_web 0.1.0) lib/metamorphic_web/endpoint.ex:1: MetamorphicWeb.Endpoint.plug_builder_call/2
    (metamorphic_web 0.1.0) lib/plug/debugger.ex:136: MetamorphicWeb.Endpoint."call (overridable 3)"/2
    (metamorphic_web 0.1.0) lib/metamorphic_web/endpoint.ex:1: MetamorphicWeb.Endpoint.call/2
    (phoenix 1.6.7) lib/phoenix/endpoint/cowboy2_handler.ex:54: Phoenix.Endpoint.Cowboy2Handler.init/4
    (cowboy 2.9.0) /home/mark/github/eclogite/deps/cowboy/src/cowboy_handler.erl:37: :cowboy_handler.execute/2
    (cowboy 2.9.0) /home/mark/github/eclogite/deps/cowboy/src/cowboy_stream_h.erl:306: :cowboy_stream_h.execute/3
    (cowboy 2.9.0) /home/mark/github/eclogite/deps/cowboy/src/cowboy_stream_h.erl:295: :cowboy_stream_h.request_process/3
    (stdlib 3.17) proc_lib.erl:226: :proc_lib.init_p_do_apply/3

Router
Below is router.ex file:

defmodule MetamorphicWeb.Router do
  use MetamorphicWeb, :router

  import Phoenix.LiveDashboard.Router
  import MetamorphicWeb.PersonAuth

  alias MetamorphicWeb.Plugs.{EnsurePrivilege, VerifyPortalPass, PlugAttack}

  if Application.get_env(:metamorphic_web, :http_headers) == :prod do
    pipeline :browser do
      plug PlugAttack
      plug :accepts, ["html"]
      plug :fetch_session
      plug :fetch_live_flash
      plug :protect_from_forgery

      plug :put_secure_browser_headers, %{
        "referrer-policy" => "no-referrer",
        "permissions-policy" => "interest-cohort=()",
        "strict-transport-security" => "max-age=31536000; includeSubDomains"
      }

      plug :fetch_current_person
    end

    pipeline :gpc do
      plug PlugAttack
      plug :accepts, ["json"]
    end
  else
    pipeline :browser do
      plug PlugAttack
      plug :accepts, ["html"]
      plug :fetch_session
      plug :fetch_live_flash
      plug :protect_from_forgery

      plug :put_secure_browser_headers, %{
        "referrer-policy" => "no-referrer",
        "permissions-policy" => "interest-cohort=()"
      }

      plug :fetch_current_person
    end

    pipeline :gpc do
      plug PlugAttack
      plug :accepts, ["json"]
    end
  end

  pipeline :api do
    plug PlugAttack
    plug :accepts, ["json"]
  end

  pipeline :marketing_layout do
    plug :put_root_layout, {MetamorphicWeb.LayoutView, :marketing}
  end

  pipeline :pre_release_layout do
    plug :put_root_layout, {MetamorphicWeb.LayoutView, :pre_release}
  end

  pipeline :register_layout do
    plug :put_root_layout, {MetamorphicWeb.LayoutView, :register}
  end

  pipeline :app_layout do
    plug :put_root_layout, {MetamorphicWeb.LayoutView, :root}
  end

  pipeline :admin do
    plug EnsurePrivilege, :admin
  end

  pipeline :person do
    plug EnsurePrivilege, [:admin, :person]
  end

  pipeline :require_portal_pass do
    plug VerifyPortalPass
  end

  # Other scopes may use custom stacks.
  # scope "/api", MetamorphicWeb do
  #   pipe_through :api
  # end

  # Enables LiveDashboard only for development
  #
  # If you want to use the LiveDashboard in production, you should put
  # it behind authentication and allow only admins to access it.
  # If your application does not have an admins-only section yet,
  # you can use Plug.BasicAuth to set up some basic authentication
  # as long as you are also using SSL (which you should anyway).
  #
  # We are using live dash in production. It is behind the admin
  # authentication and authorization.

  # Enables displaying emails via Bamboo LocalAdapter for
  # development.
  if Mix.env() == :dev do
    # If using Phoenix
    forward "/sent_emails", Bamboo.SentEmailViewerPlug
  end

  # Health check
  scope "/", MetamorphicWeb do
    pipe_through [:browser, :marketing_layout]

    get "/healthz", HealthCheckController, :index, as: :health_check
  end

  # Global Privacy Control route.
  scope "/", MetamorphicWeb do
    pipe_through [:gpc]

    get "/.well-known/gpc.json", GlobalPrivacyController, :global_privacy_response
  end

  ##
  ## Requires AUTHENTICATED person routes
  ##

  # 2FA (two-factor authentication).
  scope "/", MetamorphicWeb do
    pipe_through [:browser, :register_layout, :require_authenticated_person, :person]

    get "/people/totp", PersonTOTPController, :new
    post "/people/totp", PersonTOTPController, :create
  end

  # Subscriptions
  scope "/", MetamorphicWeb do
    pipe_through [
      :browser,
      :register_layout,
      :require_authenticated_person,
      :redirect_if_person_has_subscription
    ]

    live "/subscriptions/new", SubscriptionLive.New, :new
  end

  # Dashboard, settings, and support.
  scope "/", MetamorphicWeb do
    pipe_through [
      :browser,
      :app_layout,
      :require_authenticated_person,
      :redirect_if_admin,
      :person
    ]

    live_session :authenticated_redirect_if_admin,
      root_layout: {MetamorphicWeb.LayoutView, :root},
      on_mount: [{MetamorphicWeb.PersonLiveAuth, :redirect_if_admin}, MetamorphicWeb.Nav] do
      live "/dashboard", DashboardLive.Index, :index, as: :dashboard
      live "/people/settings", PersonSettingsLive.Index, :index, as: :person_settings
      live "/people/settings/billing", PersonSettingsLive.Billing, :billing, as: :person_settings
      live "/people/settings/data", PersonSettingsLive.Data, :data, as: :person_settings
      live "/people/settings/security", PersonSettingsLive.Security, :security, as: :person_settings
      live "/support", SupportLive.Index, :index, as: :support
    end

    get "/people/settings/data/download-stripe-data",
        PersonSettingsController,
        :download_stripe_data

    get "/people/settings/data/download-encrypted-person",
        PersonSettingsController,
        :download_encrypted_person_data

    get "/people/settings/data/download-encrypted-memories",
        PersonSettingsController,
        :download_encrypted_memory_data

    get "/people/settings/data/download-encrypted-letters",
        PersonSettingsController,
        :download_encrypted_letter_data

    get "/people/settings/data/download-encrypted-portals",
        PersonSettingsController,
        :download_encrypted_portal_data

    get "/people/settings/data/download-encrypted-person-relationships",
        PersonSettingsController,
        :download_encrypted_relationship_person_data

    get "/people/settings/data/download-encrypted-relation-relationships",
        PersonSettingsController,
        :download_encrypted_relationship_relation_data

    get "/people/settings/confirm_email/:token", PersonSettingsController, :confirm_email
    put "/people/settings/update_password", PersonSettingsController, :update_password
  end

  # Log out.
  scope "/", MetamorphicWeb do
    pipe_through [:browser, :app_layout, :require_authenticated_person, :person]

    delete "/people/log_out", PersonSessionController, :delete
  end

  # Letters, memories, relationships, portals (:index, :new, and :edit).
  scope "/", MetamorphicWeb do
    pipe_through [
      :browser,
      :app_layout,
      :require_authenticated_person,
      :require_active_subscription,
      :person
    ]

    live_session :authenticated,
      root_layout: {MetamorphicWeb.LayoutView, :root},
      on_mount: [{MetamorphicWeb.PersonLiveAuth, :ensure_authenticated}, MetamorphicWeb.Nav] do
      live "/letters", LetterLive.Index, :index, as: :letters
      live "/letters/new", LetterLive.Index, :new, as: :letters
      live "/letters/mailbox", LetterLive.Mailbox, :mailbox, as: :letters
      live "/letters/mailbox/new", LetterLive.Mailbox, :compose, as: :letters
      live "/letters/:id/read", LetterLive.Mailbox, :read, as: :letters
      # live "/letters/:id/edit", LetterLive.Index, :edit, as: :letters

      live "/memories", MemoryLive.Index, :index, as: :memories
      # live "/memories/:id/edit", MemoryLive.Index, :edit, as: :memories
      live "/memories/new", MemoryLive.Index, :new, as: :memories

      get "/memories/shared/download", MemoryDownloadsController, :download_shared_memory,
        as: :memories

      get "/memories/download", MemoryDownloadsController, :download_memory, as: :memories
      # live "/memories/:id", MemoryLive.Show, :show, as: :memories
      # live "/memories/:id/show/edit", MemoryLive.Show, :edit

      live "/portals", PortalLive.Index, :index, as: :portal
      # live "/portals/:id/edit", PortalLive.Index, :edit, as: :portal
      live "/portals/new", PortalLive.New, :new, as: :portal

      live "/relationships", RelationshipLive.Index, :index, as: :relationships
      live "/relationships/new", RelationshipLive.Index, :new, as: :relationships
      live "/relationships/:id/edit", RelationshipLive.Index, :edit, as: :relationships
      # live "/relationships/:id", RelationshipLive.Show, :show
      # live "/relationships/:id/show/edit", RelationshipLive.Show, :edit

      live "/roadmap", RoadmapLive.Index, :index, as: :roadmap
    end
  end

  # Portals (:show) with :require_portal_pass plug.
  scope "/", MetamorphicWeb do
    pipe_through [
      :browser,
      :app_layout,
      :require_authenticated_person,
      :require_active_subscription,
      :require_portal_pass,
      :person
    ]

    live "/portals/open/:slug", PortalLive.Show, :show, as: :portal
  end

  ##
  ## Does NOT require authenticated person routes
  ##

  # Registration and log in pages for people's accounts.

  scope "/", MetamorphicWeb do
    pipe_through [:browser, :register_layout, :redirect_if_person_is_authenticated]

    get "/people/log_in", PersonSessionController, :new
    post "/people/log_in", PersonSessionController, :create

    live_session :register,
      root_layout: {MetamorphicWeb.LayoutView, :register},
      on_mount: {MetamorphicWeb.PersonLiveAuth, :register} do
      live "/people/register", PersonRegistrationLive.New, :new, as: :person_registration
    end

    # get "/people/reset_password", PersonResetPasswordController, :new
    # post "/people/reset_password", PersonResetPasswordController, :create
    # live "/people/reset_password/:token", PersonResetPasswordLive.Edit, :edit, as: :person_reset_password
    # put "/people/reset_password/:token", PersonResetPasswordController, :update
  end

  # Resend confirmation instructions for a person's account.

  scope "/", MetamorphicWeb do
    pipe_through [:browser, :register_layout]

    get "/people/confirm", PersonConfirmationController, :new
    post "/people/confirm", PersonConfirmationController, :create
    get "/people/confirm/:token", PersonConfirmationController, :confirm
    get "/invitations/confirm", InviteConfirmationController, :new
    post "/invitations/confirm", InviteConfirmationController, :create
    get "/invitations/confirm/:token", InviteConfirmationController, :confirm
  end

  # Marketing pages.
  scope "/", MetamorphicWeb do
    pipe_through [:browser, :marketing_layout]

    # live_session :pre_release, root_layout: {MetamorphicWeb.LayoutView, :pre_release}, on_mount: {MetamorphicWeb.PersonLiveAuth, :pre_release} do
    # live "/", PageLive.Index, :index, as: :page
    # end

    live_session :marketing,
      root_layout: {MetamorphicWeb.LayoutView, :marketing},
      on_mount: {MetamorphicWeb.PersonLiveAuth, :marketing} do
      live "/", PageLive.Index, :index, as: :page
      live "/about", AboutLive.Index, :index, as: :about
      live "/built-to-code", BuiltToCodeLive.Index, :index, as: :built_to_code
      live "/customer-rights", CustomerRightsLive.Index, :index, as: :customer_rights
      live "/faq", FaqLive.Index, :index, as: :faq
      live "/features", FeaturesLive.Index, :index, as: :features
      live "/find-your-peace", FindYourPeaceLive.Index, :index, as: :find_your_peace
      live "/hassle-free", HassleFreeLive.Index, :index, as: :hassle_free
      live "/pricing", PricingLive.Index, :index, as: :pricing
      live "/privacy", PrivacyLive.Index, :index, as: :privacy
      live "/security", SecurityLive.Index, :index, as: :security
      live "/rocks", SpecialThanksLive.Index, :index, as: :thanks
      live "/terms", TermsLive.Index, :index, as: :terms
      live "/why-metamorphic", WhyMetamorphicLive.Index, :index, as: :why_metamorphic

      live "/blog", BlogLive.Index, :index, as: :blog

      live "/blog/clean-cookies", BlogLive.Posts.CleanCookies, :index,
        as: :blog_posts_clean_cookies

      live "/blog/early-access-sign-ups", BlogLive.Posts.EarlyAccessSignUps, :index,
        as: :blog_posts_early_access_sign_ups

      live "/blog/markdown-guide", BlogLive.Posts.MarkdownGuide, :index,
        as: :blog_posts_markdown_guide
    end
  end

  # Pre-release invitations page.
  # scope "/", MetamorphicWeb do
  #  pipe_through [:browser, :pre_release_layout]

  # live "/", PageLive.Index, :index, as: :page
  # end

  ##
  ## Requires ADMIN AUTHENTICATED routes.
  ##

  scope "/odus", MetamorphicWeb do
    pipe_through [:browser, :app_layout, :require_authenticated_person, :admin]
    live_dashboard "/sys_dash", metrics: MetamorphicWeb.Telemetry
  end

  scope "/odus", MetamorphicWeb do
    pipe_through [:browser, :app_layout, :require_authenticated_person, :admin]

    live_session :admin,
      root_layout: {MetamorphicWeb.LayoutView, :root},
      on_mount: [{MetamorphicWeb.PersonLiveAuth, :admin}, MetamorphicWeb.Nav] do
      live "/dashboard", DashboardLive.Admin, :admin, as: :admin_dashboard
      live "/invitations", InviteLive.Admin, :admin, as: :admin_invite
      live "/invitations/new", InviteLive.Admin, :admin_new, as: :admin_invite_new
      live "/invitations/:id/edit", InviteLive.Admin, :admin_edit, as: :admin_invite_edit
      live "/invitations/:id", InviteLive.Show, :show
      live "/invitations/:id/show/edit", InviteLive.Show, :edit
      live "/people/settings", PersonSettingsLive.Admin, :admin, as: :admin_settings
      live "/roadmap", RoadmapLive.Admin, :admin, as: :admin_roadmap
      live "/roadmap/new", RoadmapLive.Admin, :admin_new, as: :admin_roadmap_new
      live "/roadmap/:id/edit", RoadmapLive.Admin, :admin_edit, as: :admin_roadmap_edit
      live "/roadmap/:id/update", RoadmapLive.Admin, :admin_update, as: :admin_roadmap_update
      live "/roadmap/:id/delete", RoadmapLive.Admin, :admin_delete, as: :admin_roadmap_delete
      live "/support", SupportLive.Admin, :admin, as: :admin_support
    end

    get "/people/settings/data/download-encrypted-admin",
        PersonSettingsController,
        :download_encrypted_admin_data

    get "/people/settings/confirm_email/:token", PersonSettingsController, :confirm_email
    put "/people/settings/update_password", PersonSettingsController, :update_password
    delete "/people/log_out", PersonSessionController, :delete
  end
end

Marked As Solved

wkirschbaum

wkirschbaum

Another solution will be to change the url option to action. It seems like the csrf token only gets added if the action gets set.

<.form let={f} for={@conn} action={Routes.person_session_path(@conn, :create)} as={:person}>
  ...
</.form>

Also Liked

weego

weego

We had the same issue with our activation page and had to add the csrf_input_tag in manually. I am assuming this is a bug.

Where Next?

Popular in Questions Top

hariharasudhan94
lets say i have a sample like a = 20; b = 10; if (a &gt; b) do {:ok, "a"} end if (a &lt; b) do {:ok, b} end if (a == b) do {:ok, "equa...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
Tee
can someone please explain to me how Enum.reduce works with maps
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New

Other popular topics Top

WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
nobody
Hi! In PHP: $_SERVER[‘SERVER_ADDR’] - in Elixir? Searched the docs for ip address and the web, no good results. Thanks!
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36352 110
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 54120 245
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement