harlan-zw / unlighthouse

Scan your entire site with Google Lighthouse in 2 minutes (on average). Open source, fully configurable with minimal setup.
https://unlighthouse.dev
MIT License
3.65k stars 105 forks source link

Failing to read localStorage (access denied) on page.setCookie() #182

Closed transreport-marley closed 4 months ago

transreport-marley commented 5 months ago

Describe the bug

Hey 👋,

I am just in the process of setting up unlighthouse for a proof of concept. The application itself (aside from /login) is locked behind authentication, so I am using the authenticate() hook to do a POST to our login API, get the required access_token & refresh_token and then use await page.setCookie({ ... }) so it can access URLs locked behind our auth middleware.

Here's the current unlighthouse.config.ts:

export default {
  hooks: {
    async authenticate(page) {
      await fetch('...', {
        method: 'POST',
        body: JSON.stringify({ ... }),
      })
        .then((r) => { ... })
        .then(
          async ({
            access_token: accessToken,
            refresh_token: refreshToken,
          }) => {
            await page.setCookie({
              name: 'access-token',
              value: accessToken,
              domain: 'localhost',
              path: '/',
            });

            await page.setCookie({
              name: 'refresh-token',
              value: refreshToken,
              domain: 'localhost',
              path: '/',
            });
          },
        )
        .catch((err: any) => { ... });
    },
  },
  debug: true,
  puppeteerOptions: {
    headless: false,
  },
  puppeteerClusterOptions: {
    maxConcurrency: 1,
  },
  site: 'http://localhost:3000/login',
  urls: ['/'],
};

As it stands I am only running it on the one URL (behind auth) for debugging. Though the fetch succeeds, returns the expected access_token and refresh_token, however, when I go to set these using setCookie it runs into a permissions issue:

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

Initially, I followed the Programmatic Usage approach, though due the redirects that happen in our authentication flow it didn't work. I have also been through Troubleshooting as you can see in the config, as well as going through the GH issues to see if anyone has ran into this.

It's a bit of a head-scratcher and I am likely missing something painfully obvious.

Any suggestions would be very much appreciated, cheers! 🙇

Reproduction

No response

System / Nuxt Info

MacOS, Chrome, Nuxt 3 application (running on localhost:3000, Node 18).
transreport-marley commented 5 months ago

@harlan-zw I don't suppose you've experienced something like this before? I am still scratching my head and can't find a solution.

harlan-zw commented 5 months ago

Hi @transreport-marley, thanks for the issue.

I'd assume the issue is that the page does not currently have a context, you should visit a URL of your site before setting the cookie. Unlighthouse can't safely do this for you as it doesn't know what is authenticated before this hook is ran.

await page.goto('https://mysite.com)