manchenkoff / nuxt-auth-sanctum

Nuxt module for Laravel Sanctum authentication
https://manchenkoff.gitbook.io/nuxt-auth-sanctum/
MIT License
116 stars 16 forks source link

[Docs] Keep client headers during SWR mode #94

Closed MittyBoro closed 1 month ago

MittyBoro commented 1 month ago

Describe the bug When using SWR for route rules there is no user data

To Reproduce Steps to reproduce the behavior:

nuxt.config:

// ...
  ssr: true, 
  routeRules: {
    '/': { ssr: true },  // has user data after page reload, it's ok
    '/about': { swr: 100 }, // useSanctumUser() is empty (null)
  },
// ...

Module information

export default defineNuxtConfig({
    '@nuxt/fonts',
    '@nuxt/image', 
    '@nuxtjs/color-mode',
    '@nuxtjs/sitemap', 
    'nuxt-auth-sanctum', 
    'nuxt-delay-hydration',
    'nuxt-gtag', 
    'nuxt-icon',
    'nuxt-purgecss',
    'nuxt-schema-org', 

    sanctum: {
      baseUrl: process.env.BACKEND_URL + '/api/v1', // Laravel API
      endpoints: {
        csrf: '/../../sanctum/csrf-cookie',
        login: '/../auth/login',
        logout: '/../auth/logout',
        user: '/users/me',
      },
  },
});

Nuxt environment:

Additional context

/nuxt-auth-sanctum/dist/runtime/httpFactory.mjs:45

  function buildServerHeaders(headers) {
    const clientCookies = useRequestHeaders(["cookie"]);

ssr - has cookie swr - empty

Any ideas on how to fix this?

manchenkoff commented 1 month ago

Hey @MittyBoro, thanks for opening this! I personally never tried to use it with SWR since I was primarily focused on CSR/SSR support. After a quick check of Nuxt docs, I am not even sure that it is compatible with those methods.

Here they claim that useRequestHeaders may return an empty result when using in the browser - useRequestHeaders docs, and also SWR is described as full cache on server side or reverse proxy (which might be nginx) unless API response changes, in this case I assume the plain HTML will be returned resulting in incompatibility with authentication middleware and so on.

I can dive into this one in a couple of weeks once I have time, but in the meantime, you can stick to either CSR/SSR or use SWR for pages that don't require authentication data

MittyBoro commented 1 month ago

Here pi0 mentioned that we can disable caching of part of the header in the nitro configuration.

nuxt.config:

// ...
  ssr: true, 
  routeRules: {
    '/': { ssr: true },  
    '/about': { swr: 100, cache: { varies: ['cookie'] } },
  },
// ...

It works well for me

I think you can mention this in the documentation.

At the moment, I don't know if there are any other solutions or how good this one is. We need to delve deeper into this issue.

UPD. It works locally, but still not in production. I need to delve deeper into this.

MittyBoro commented 1 month ago

Yes, adding varies to nuxt.config.ts works on production as well.

Also, need to specify origin in the nuxt-auth-sanctum configuration or exclude it in routeRules.

export default defineNuxtConfig({
  // ...
  ssr: true,
  routeRules: {
    '/about': {
      maxAge: 60*60,
      swr: true,
      varies: [
        'cookie',
        'origin' // here
      ],
    },
  },
  sanctum: {
    origin: 'your website', // or here
    // ...
  },
})

I had a CORS problem (requires attention). And there was an nginx error due to cookie forwarding (502 error: upstream sent too big header while reading response header from upstream). I needed to configure nginx proxy_pass (approx.)

location / {
  #...
  proxy_buffer_size   128k;
  proxy_buffers   4 256k;
  proxy_busy_buffers_size   256k;
  proxy_pass http://127.0.0.1:3000; #
}

I hope this helps someone.

Maybe there's a way to improve the auth module, but I haven't found it yet.

manchenkoff commented 1 month ago

Thanks for great explanation @MittyBoro, I'll do some tests and will post your findings into the documentation as well. I think it might be very useful for others. As for improvements, it looks like it is more low-level configuration than the module itself, but I will check if there is a way to determine if swr is used, maybe it is possible to dynamically change the config or at least show warnings for developers.

manchenkoff commented 1 month ago

Hey @MittyBoro, I double-checked the SWR behavior following your example and it looks like it doesn't work.

The code I used in the playground:

routeRules: {
    '/profile': {
        cache: {
            varies: ['origin', 'cookie'],
            swr: true,
            maxAge: 3600,
        },
    },
},

Yes, authentication works fine and after the page refresh it still shows proper data, but it is not actually cached. You can check the stale response by going to YOUR_APP/.nuxt/cache/nitro/routes/_/YOUR_ROUTE and see that every page refresh generates a new cached response due to dynamic headers returning by the Laravel app.

I also checked Nuxt and Nitro docs and it looks like there is no way to determine if SWR is used on the module side, so I cannot show any warning or add support for these kinds of pages.

As I mentioned previously, caching makes sense for those pages/components that are not changed based on dynamic values for each request/user.

I'm closing this one for now, feel free to re-open in case of further questions.