We recently had cause to run a Phoenix application within an iframe on another application. We’d managed to have an application working just fine inside the iframe for a standalone HTML page and a simple Vue app. However when we came to try the Phoenix app we were getting blocked by an error:
Refused to display <blah> in a frame because it set 'X-Frame-Options' to 'sameorigin'.
In order to get our application to display we needed to remove the ‘X-Frame-Options’ header from the response we were sending. In Phoenix this header (among others) is added by default through a plug in the router, put_secure_browser_headers/2.
To solve this we created a custom plug that would authenticate the request and then remove the header from the response on success. Phoenix has a handy function delete_resp_header/2 that lets us do just that.
# controllers/allow_cross_origin_iframe.ex defmodule CultivateWeb.AllowCrossOriginIframe do import Plug.Conn def init(opts), do: opts def call(conn, _options) do conn |> authenticate_source() |> delete_resp_header("x-frame-options") end defp authenticate_source(conn) do # check that source is allowed to delete header end end
This plug can then be added to the router pipeline.
defmodule CultivateWeb.Router do use CultivateWeb, :router pipeline :browser do plug :accepts, ["html"] plug :fetch_session plug :fetch_flash plug :protect_from_forgery plug :put_secure_browser_headers plug CultivateWeb.AllowCrossOriginIframe end scope "/", CultivateWeb do pipe_through :browser get "/", PageController, :index end end
Is there a better way to solve this issue? Let us know!