diff --git a/docs/content/1.getting-started/1.introduction.md b/docs/content/1.getting-started/1.introduction.md index 8d12332a..2e08608c 100644 --- a/docs/content/1.getting-started/1.introduction.md +++ b/docs/content/1.getting-started/1.introduction.md @@ -89,11 +89,11 @@ Supabase 'service role key', has super admin rights and can bypass your Row Leve ### `useSsrCookies` -Default: `true` +Default: `true` when SSR is enabled, `false` when `ssr: false`. Controls whether the module uses cookies to share session info between server and client. You *must* enable this option if you need to access session or user info from the server. It will use the SSR client from the [@supabase/ssr](https://github.com/supabase/ssr) library. -When disabled, the module will use the default Supabase client from the [@supabase/supabase-js](https://github.com/supabase/supabase-js) library which stores session info in local storage. This is useful in certain cases, such as statically generated sites or mobile apps where cookies might not be available. +When disabled, the module will use the default Supabase client from the [@supabase/supabase-js](https://github.com/supabase/supabase-js) library which stores session info in local storage. This is useful in certain cases, such as SPA/CSR-only apps, statically generated sites or mobile apps where cookies might not be available. ::warning When `useSsrCookies` is `true` the following options cannot be customized with `clientOptions`: diff --git a/docs/content/1.getting-started/2.authentication.md b/docs/content/1.getting-started/2.authentication.md index ef105ca3..4f909913 100644 --- a/docs/content/1.getting-started/2.authentication.md +++ b/docs/content/1.getting-started/2.authentication.md @@ -13,6 +13,12 @@ All you need to do is to create a `login.vue` and `confirm.vue` page in the `pag For advanced users who want to implement the auth behaviour themselves, you can disable or override the [redirect options](/getting-started/introduction#redirect). :: +## SPA / CSR-only mode + +When your Nuxt app uses `ssr: false`, the module defaults [`useSsrCookies`](/getting-started/introduction#usessrcookies) to `false` so the browser client can restore the session from local storage before auth middleware runs. This keeps authenticated users signed in after a hard refresh in SPA mode. + +If you explicitly enable `useSsrCookies` in an SPA, make sure you handle session hydration yourself before protected-route redirects run. + ## Log-in page - `/login` Each time a user is trying to access a page that needs authentication, he will automatically be redirected to the configured log in page. If you want to allow access to "public" page, you just need to add them in the [exclude](/getting-started/introduction#redirectoptions) redirect option. Alternatively, you can enable the redirect only for certain routes using the [include](/getting-started/introduction#redirectoptions) redirect option. @@ -197,4 +203,3 @@ watch(newPassword, () => { ``` If you want to learn more about it, you can read this [section](https://supabase.com/docs/reference/javascript/auth-resetpasswordforemail). - diff --git a/src/module.ts b/src/module.ts index 3d68b8a8..2586a3e2 100644 --- a/src/module.ts +++ b/src/module.ts @@ -7,6 +7,7 @@ import type { CookieOptions } from 'nuxt/app' import type { SupabaseClientOptions } from '@supabase/supabase-js' import type { NitroConfig, NitroRouteConfig } from 'nitropack' import type { RedirectOptions } from './types' +import { resolveUseSsrCookies } from './utils/resolveUseSsrCookies' export * from './types' @@ -87,7 +88,7 @@ export interface ModuleOptions { * Some `clientOptions` are not configurable when this is enabled. See the docs for more details. * * If false, the server will not be able to access the session. - * @default true + * @default true when ssr is enabled, false when ssr: false * @type boolean */ useSsrCookies?: boolean @@ -153,7 +154,7 @@ export default defineNuxtModule({ }, cookieName: 'sb', cookiePrefix: undefined, - useSsrCookies: true, + useSsrCookies: undefined, cookieOptions: { maxAge: 60 * 60 * 8, sameSite: 'lax', @@ -165,6 +166,7 @@ export default defineNuxtModule({ setup(options, nuxt) { const logger = useLogger('@nuxt/supabase') const { resolve, resolvePath } = createResolver(import.meta.url) + const useSsrCookies = resolveUseSsrCookies(options.useSsrCookies, nuxt.options.ssr) // Public runtimeConfig nuxt.options.runtimeConfig.public.supabase = defu(nuxt.options.runtimeConfig.public.supabase, { @@ -174,7 +176,7 @@ export default defineNuxtModule({ redirectOptions: options.redirectOptions, cookieName: options.cookieName, cookiePrefix: options.cookiePrefix, - useSsrCookies: options.useSsrCookies, + useSsrCookies, cookieOptions: options.cookieOptions, clientOptions: options.clientOptions, }) diff --git a/src/utils/resolveUseSsrCookies.ts b/src/utils/resolveUseSsrCookies.ts new file mode 100644 index 00000000..6e255891 --- /dev/null +++ b/src/utils/resolveUseSsrCookies.ts @@ -0,0 +1,3 @@ +export function resolveUseSsrCookies(useSsrCookies: boolean | undefined, ssr: boolean) { + return useSsrCookies ?? ssr !== false +} diff --git a/test/resolveUseSsrCookies.test.ts b/test/resolveUseSsrCookies.test.ts new file mode 100644 index 00000000..9548bfb4 --- /dev/null +++ b/test/resolveUseSsrCookies.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, it } from 'vitest' +import { resolveUseSsrCookies } from '../src/utils/resolveUseSsrCookies' + +describe('resolveUseSsrCookies', () => { + it('defaults to true when Nuxt SSR is enabled', () => { + expect(resolveUseSsrCookies(undefined, true)).toBe(true) + }) + + it('defaults to false when Nuxt SSR is disabled', () => { + expect(resolveUseSsrCookies(undefined, false)).toBe(false) + }) + + it('preserves explicit configuration', () => { + expect(resolveUseSsrCookies(true, false)).toBe(true) + expect(resolveUseSsrCookies(false, true)).toBe(false) + }) +})