vercel / next.js

The React Framework
https://nextjs.org
MIT License
126.78k stars 26.95k forks source link

Next.js throws an exception when running in 3rd party iframe #34848

Open artooras opened 2 years ago

artooras commented 2 years ago

Verify canary release

Provide environment information

Running the suggested commands failed to produce an output in the sandbox I have created to reproduce the issue. However, perhaps the relevant parameters can be looked up in the sandbox itself:

https://codesandbox.io/s/young-https-mdcctx

It's a clean template running the latest version of Next.js.

What browser are you using? (if relevant)

Chrome (latest version) - 3rd party cookies disabled

How are you deploying your application? (if relevant)

next dev

Describe the Bug

My example reproduces the behaviour when running Next.js in a 3rd party iframe - merely running a basic Next.js app in such a setup throws an exception (see console).

Demo website - https://rightsize-store.000webhostapp.com/next_js_test.html Sandbox - https://codesandbox.io/s/young-https-mdcctx

Here's the error:

Error was not caught DOMException: Failed to read the 'localStorage' property from 'Window': Access is denied for this document.
    at initializeBuildWatcher (webpack-internal:///./node_modules/next/dist/client/dev/prerender-indicator.js:47:38)
    at eval (webpack-internal:///./node_modules/next/dist/client/next-dev.js:96:40)

In my actual application (too complex to easily reproduce in a sandbox) Next.js is throwing a similar exception:

Uncaught (in promise) DOMException: Failed to read the 'sessionStorage' property from 'Window': Access is denied for this document.
    at clearFullRefreshStorage (webpack-internal:///./node_modules/next/dist/client/dev/error-overlay/hot-dev-client.js:314:3)
    at handleApplyUpdates (webpack-internal:///./node_modules/next/dist/client/dev/error-overlay/hot-dev-client.js:265:5)
    at eval (webpack-internal:///./node_modules/next/dist/client/dev/error-overlay/hot-dev-client.js:287:5)

Looking into the usage of clearFullRefreshStorage inside internal Next.js files I can see that sessionStorage is manipulated not wrapped in a try/catch block. Is that intentional?

Expected Behavior

I would expect that Next.js would work in all environments, including increasingly more restrictive of accessing cookies and web storage.

To Reproduce

Simply visit https://rightsize-store.000webhostapp.com/next_js_test.html and look at console logs.

balazsorban44 commented 2 years ago

Not sure I fully understand, but are you trying to develop a Next.js app from within an iframe?

localStorage and sessionStorage are only allowed in the same domain, so if your iframe is embedded in a different domain then the Next.js server, it might produce the mentioned issue. This is not a Next.js bug, but how the above-mentioned Web APIs operate. Make sure your iframe embeds a url on the same domain.

artooras commented 2 years ago

Hi @balazsorban44. I'm not sure I fully understand your question either :) My repro speaks for itself, doesn't it? I'm simply loading a basic Next.js app inside an iframe, and it throws an exception from its internal methods. I.e. I am not trying to use the Web APIs from a cross-domain - if I were to do that, I would wrap them inside a try/catch block.

Is there something in my repro that doesn't illustrate the issue? https://rightsize-store.000webhostapp.com/next_js_test.html (run in Chrome with 3rd party cookies disabled)

I am building an app with Next.js that can be embedded by other websites as an iframe.

balazsorban44 commented 2 years ago

Failed to read the 'localStorage' property from 'Window': Access is denied for this document.

This error is not thrown by Next.js, but by the browser. Disabling third-party cookies also block access to localStorage and sessionStorage.

The request violates a policy decision, ... For example, the user may have their browser configured to deny permission to persist data for the specified origin.

https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage#exceptions

So you explicitly deny access to APIs that the Next.js dev server relies on.

In production, this won't be a problem unless you explicitly use one of these APIs, as the production build of Next.js does not rely explicitly on localStorage or sessionStorage

balazsorban44 commented 2 years ago

Did some digging, and the only place we reference sessionStorage in development is this file: https://github.com/vercel/next.js/blob/canary/packages/next/client/dev/error-overlay/hot-dev-client.js

We use sessionStorage to make the full refresh notification modal dismissable (only show up once).

I'll check with the rest of the team about the expectations here. :+1:

artooras commented 2 years ago

That would be great, thank you. Because I think it's important for dev to behave as prod, otherwise development/testing becomes hugely complicated.

balazsorban44 commented 2 years ago

The code causing the exception is never shipped to production as it's part of the hot module overlay.

As per our recommendation, testing should happen against a production build anyway, as the development environment is not optimized for performance but developer experience.

artooras commented 2 years ago

I did some investigation and noticed that a change in behaviour occured between version 12.0.7 and 12.0.8. If I run my code (next dev) with 12.0.7 and run my application inside an iframe, everythin works fine, no exceptions are thrown. However, from 12.0.8 onwards, these exceptions appear.

balazsorban44 commented 2 years ago

That's where the full-refresh modal warning was introduced. :+1: I'll reopen this while investigating.

artooras commented 2 years ago

@balazsorban44, any updates on this? Thanks!

artooras commented 2 years ago

Hi @balazsorban44. Any updates on this yet? I'm stuck on v12.0.7 with this issue still open...

cotarelorodrigo commented 1 year ago

Any news about this? I have clients that show my web with an iframe in their mobile apps. Some users are getting this error

julianourias commented 1 year ago

Solved it by using the following cookie options:

cookies: { sessionToken: { name: `next-auth.session-token`, options: { path: '/', httpOnly: true, sameSite: 'none', secure: true, }, }, callbackUrl: { name: `next-auth.callback-url`, options: { path: '/', sameSite: 'none', secure: true, }, }, csrfToken: { name: `next-auth.csrf-token`, options: { path: '/', httpOnly: true, sameSite: 'none', secure: true, }, }, },

https://github.com/nextauthjs/next-auth/issues/1497