NextJS with X-Content-Type-Options header breaks previews

Hey Prismic team,

I discovered that adding the X-Content-Type-Options header with the nosniff value breaks previews. With this header in place, opening a preview in the latest versions of Chrome and Firefox either downloads a file with this content or shows this content in-browser:

<!DOCTYPE html><html><head><meta http-equiv="Refresh" content="0; url=${redirectUrl}" />
    <script>window.location.href = '${redirectUrl}'</script>
    </head>

This is likely coming from the following workaround that we have to use in the NextJS api/preview route:

// Redirect the user to the share endpoint from same origin. This is
// necessary due to a Chrome bug:
// https://bugs.chromium.org/p/chromium/issues/detail?id=696204
res.write(`
  <!DOCTYPE html><html><head><meta http-equiv="Refresh" content="0; url=${redirectUrl}" />
  <script>window.location.href = '${redirectUrl}'</script>
  </head>`
);

This is my vercel.json:

{
  "headers": [
    {
      "source": "/service-worker.js",
      "headers": [
        {
          "key": "Cache-Control",
          "value": "public, max-age=0, must-revalidate"
        }
      ]
    },
    {
      "source": "/(.*)",
      "headers": [
        {
          "key": "X-Frame-Options",
          "value": "DENY"
        },
        {
          "key": "X-Content-Type-Options",
          "value": "nosniff"
        },
        {
          "key": "X-XSS-Protection",
          "value": "1; mode=block"
        }
      ]
    }
  ],
  ...

Removing the header allows previews to work again. I do not have enough knowledge about how previews work internally so this may be a misconfiguration issue, but having the header in place seems to be good practice in terms of security.

Should this be documented somewhere?

Hey Osama,

It's good to see you back.

Thanks for pointing this out. I'm guessing it's got something to do with how the content is passed from the cookie to Next.js' preview system.

I'll make a note to add this is the next.js preview documentation. I'll also confirm with the team about why exactly this breaks it.

This has been added to our documentation backlog. We'll update this thread when that's done.