Cookie not set in Chrome with @supabase/auth-helpers-nextjs
tomelliot opened this issue · comments
Bug report
- I confirm this is a bug with Supabase, not with my own application.
- I confirm I have searched the Docs, GitHub Discussions, and Discord.
Describe the bug
- I'm working on a Next.js app that gets built as a static bundle (output: "export" in next.config.js).
- I'm using the OTP/token auth method (sending an email to the user's email address with a OTP).
- Because this is a static bundle, there's no server side component (and so there's no setting/receiving cookies from the Next.js backend).
- I am creating a client by
const supabase = createPagesBrowserClient<Database>();
- Using
await supabase.auth.verifyOtp()
(from @supabase/auth-helpers-nextjs) I see the user being logged in and the session being set successfully. - In Firefox it works as expected.
- In Chrome:
- I can see that the response to the /verify request has Set Cookie for both sb-access-token and sb-refresh-token.
- As soon as the user refreshes the page the session is lost.
In Chrome
the Network response shows both Set Cookie headers:
The "Cookies" tab for the request shows only one of the cookies:
The Cookies for the localhost domain don't contain either of the sb-...
cookies
To Reproduce
I'm working on a minimal reproduction
Expected behavior
Session to persist on both Chrome and Firefox.
Additional context
Chrome version 118.0.5993.96 (Official Build) (arm64)
npm list | grep supabase
├── @supabase/auth-helpers-nextjs@0.8.7
├── @supabase/supabase-js@2.38.0
├── supabase@1.112.0
Same question on Discord (so far unanswered)
Workaround:
- Use the
supabase-js
createClient instead of@supabase/auth-helpers-nextjs
- Use custom storage handlers
import { SupabaseClient, createClient } from '@supabase/supabase-js';
import { deleteCookie, getCookie, setCookie } from 'cookies-next';
supabase:SupabaseClient = createClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
{
auth: {
storage: {
getItem(key) {
return getCookie(key) || null;
},
setItem(key, value) {
return setCookie(key, value, {
httpOnly: false,
sameSite: 'none',
maxAge: Date.now() + 1000 * 60 * 60 * 24 * 365,
expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365),
secure: typeof document !== 'undefined' && (document.location?.protocol === 'https' || document.location?.hostname === 'localhost'),
});
},
removeItem(key) {
return deleteCookie(key, { sameSite: 'none', secure: true });
},
},
},
},
);
Note that this is setting sameSite to none
which is unsafe.
Modified from #437 (comment)
Thanks for lodging an issue - sorry for the delay in getting back to you!
The auth-helpers
and ssr
packages are only required to store the session in a cookie making it available serverside. If everything is static with Supabase Auth only being used client-side, using @supabase/supabase-js
is the right way to go 👍
You shouldn't need to override the default storage behaviour, as localStorage
will be available client-side. This should be fine 👇
import { createClient } from '@supabase/supabase-js';
const supabase = createClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY,
);