sanity-io / next-sanity

Sanity.io toolkit for Next.js

Home Page:https://www.sanity.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Visual Editing X-Frame-Options denied

gislitg opened this issue · comments

I am trying out Visual Editing and the Presentation tool in sanity studio.
I am assuming I need to set the .env variable SANITY_STUDIO_PREVIEW_URL to my nextjs frontend production domain.
I deployed to production to test out the Visual Editing inside sanity.studio (hosted on a different domain). I am getting an error:
“Refused to display {url} in a frame because it set ‘X-Frame-Options’ to ‘deny’.”

I have Vercel Authentication on, so that could be related.

To Reproduce

Steps to reproduce the behavior:

  1. Set up Visual Editing in the same way as the repo at sanity-template-template-nextjs-personal-website
  2. localhost works well
  3. After deploying the NextJS frontend to production, sanity.studio can't connect to the Presentation of it

Expected behavior

Expected to connect to NextJS frontend

Which versions of Sanity are you using?

Sanity version 3.20.1

What operating system are you using?

MacOS Sonoma

Which versions of Node.js / npm are you running?

Node v18.18.2

There's two possible fixes you can try:

  1. Update your next.config with X-Frame-Options and Content-Security-Policy headers:
    async headers() {
      return [
        {
          source: '/:path*',
          headers: [
            {
              key: 'X-Frame-Options',
              value: 'SAMEORIGIN',
            },
            {
              key: 'Content-Security-Policy',
              value: `frame-ancestors 'self' https://my-studio.sanity.studio`,
            },
          ],
        },
      ];
    }
    Important to note that it's not safe to use value: frame-ancestors 'self' https://*.sanity.studio,, only use * if you own and control the TLD.
  2. Vercel Authentication, depending on your configuration, might not respect the headers set in step 1. And you'll need to setup Automation Bypass and use an alternate deployment method than sanity deploy. Again, to implement bypass securely you must set the x-vercel-protection-bypass URL parameter in a way that doesn't leak these parameters in the generated browser bundle. The right way of doing this takes work and is a bit involved, so test it by hardcoding the x-vercel-protection-bypass and x-vercel-set-bypass-cookie, parameters first, and if it turns out option 2 is required I'll follow up with a walkthrough of how to safely do this in production. After turning on bypass for automation and you hit "Save" it'll generate a secret you can copy, paste it in your presentationTool config:
    presentationTool({
      previewUrl: {
        origin: `https://my-app.vercel.app`,
        draftMode: {enable: `/api/draft?x-vercel-protection-bypass=ThokvDu5HW3CSJ24lAxSQmXtRdZfBWHr&x-vercel-set-bypass-cookie=samesitenone`}
      }
    })
    Test this using sanity dev, and let me know if you want the walkthrough for how to do this securily on a production deployment.

Temporary workaround

A temporary workaround you can use is to open the iframe URL directly, in order for the cookie to be set. Refreshing the Presentation Tool afterwards should solve the problem. Naturally this is only a viable workaround for users that are comfortable messing with URLs and browser devtools.

@stipsan Thanks again for the help, I am past the Content-Security-Policy error now, and the frame starts to load, I can even see the blurred contents of the page inside sanity studio, however it's forever loading
Screenshot 2023-11-28 at 14 54 32

in the console on prod there is only one error (works locally):

8593596e-e10f59b5061b90e1.js:1 Uncaught Error: Minified React error #329; visit https://reactjs.org/docs/error-decoder.html?invariant=329 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
    at oY (8593596e-e10f59b5061b90e1.js:1:92665)
    at MessagePort.x (26037-b96b799741fd0ab1.js:6:29499)

Stega should work for production builds, right? Reason I ask is because in the documentation there are checks for production setting stega to false, so it's a bit confusing.

stega: { // Enable stega if it's a Vercel preview deployment enabled: process.env.VERCEL_ENV !== 'production', },

As a side note, the Vercel preview deployments work correctly with the Toolbar and edit button. Preview displays overlays and routes correctly to sanity.studio, it's super nice 👍

Alright, almost there!
I'm unsure what the Error: Minified React error #329 could be. The warning you should be seeing is something like:

react_devtools_backend_compact.js:12966 Unable to connect to overlays. Make sure you're calling the 'enableOverlays' function in '@sanity/overlays' correctly, and that its 'allowStudioOrigin' property is set to 'https://my-studio.sanity.studio/'

For the moment the allowStudioOrigin property, in both enableOverlays as well as for useLiveMode, is a single string and must be exact.
We have in our backlog plans for adding an array over known origins, and we're considering adding * wildcard support similar to how you manage CORS in other web platform features, such as Access-Control-Allow-Origin headers.
Until then we recommend setting it as an env var that you can then override on specific preview deployments as a workaround:

const allowStudioOrigin = process.env.NEXT_PUBLIC_SANITY_STUDIO_ORIGIN || 'http://localhost:3333'

export default function VisualEditing() {
  useLiveMode({allowStudioOrigin})
  useEffect(() => enableOverlays({allowStudioOrigin}), [])
}

We're open for feedback on other ways we could make this more manageable :)

Still getting the Unable to connect to overlays error 🤔
I am sure my STUDIO_ORIGIN is correct and I am enabling Overlays...

I see, are you able to produce and share a minimal reproduction github repository? Sounds like we may have a bug 🤔

Hey @stipsan sorry for the late reply here! This issue resolved itself with your help regarding X-Frame-Options for Vercel Authentication. We still had some issues connection after that, but after updating to the latest versions, everything just worked. Closing this as it is resolved, thanks for the help 🙏