nuxt-modules / supabase

Supabase module for Nuxt.
https://supabase.nuxtjs.org
MIT License
693 stars 127 forks source link

useSupabaseUser() is not updated until I leave the browser window or switch browser tabs #144

Closed anderslutzhoft closed 1 year ago

anderslutzhoft commented 1 year ago

I'll apologize in advance if this is a beginner's question, but I've tried searching for an answer, and I can't seem to find any addressing the issue I have.

I use this module and I can successfully login using email and password, but for some reason, the user session is not updated within useSupabaseUser() until I leave the browser window or switch tabs and come back. Even if I refresh the page the useSupabaseUser() is not up to date. I have tried watchers, plugins, etc., but to no avail. But as soon as I leave the browser window for a second, everything is updated and working as expected.

I would be really grateful if anyone could point me in the right direction!

CareTiger commented 1 year ago

I am having this same issue. Why was this closed?

anderslutzhoft commented 1 year ago

I've tried both npm run dev and Netlify Dev locally and neither works. It doesn't work when deploying to Netlify, I get a 404 on a supabase call.

I've tried Chrome, Safari, and Firefox.

The auth tokens cookies are also set properly.

bayramorhan commented 1 year ago

signInWithOAuth method is not returning any session data. If you want to work around with using signInWithOAuth and Nuxt 3, here is my solution. It works like a charm (even on mobile browsers like Safari, Chrome). anyone can use this solution until fix is realeased.

myComposable.js

const supabaseClient = useSupabaseClient();

const oAuthHandler = async (provider) => {
        try {
          const { data, error } = await supabaseClient.auth.signInWithOAuth({
            provider: provider,
          });
          if (error) throw Error(error);
        } catch (err) {
          alert(err?.message || "unknown error on sign in");
        }
      };
supabaseClient.auth.onAuthStateChange((_, _session) => {
      if(_session?.access_token) {
        const accessToken = useCookie('sb-access-token')
        const refreshToken = useCookie('sb-refresh-token')
        accessToken.value = _session?.access_token ?? null
        refreshToken.value = _session?.refresh_token ?? null
      }
    })
anderslutzhoft commented 1 year ago

@bayramorhan hi! It might not be the same issue. I get session data from the client and cookies are set. It's just the useSupabaseUser() that is not updated accordingly. Great workaround otherwise!

bayramorhan commented 1 year ago

hi @anderslutzhoft . I also experienced your exact problem. After oAuth is complete and redirected, nothing changes, there is no session data. But as soon as I switch between tabs, the data was there. So, populating session data with useCookie() fixed my problem. Im just curious about what is different on your code and why this workaround is not solving your problem. maybe you can share some code.

infyplus commented 1 year ago

Hi, i've been struggling with this issue for a while now. The session cookies are only set after i switch the tab etc.. and this is what i cameup with using getSession and refreshSession using supabase client as in the docs. Dont know if this is the right way but works for now(NB: only in non SRR mode)

 export default defineNuxtRouteMiddleware(async(to, _from) => {
  const supabase =  useSupabaseClient()
  let {data}= await supabase.auth.getSession()
if(!data.session){
  const { data, error } = await supabase.auth.refreshSession()
  let {user} = data 
  if(!user){
    return navigateTo('/login')
  }
}else{
  if(!data.session.user){
    return navigateTo('/login')
  }
}
  })

I havent really tested out if the refreshSession is actually required, and i think not, but i just put it there as a failsafe

bayramorhan commented 1 year ago

Hi, i;ve been struggling with this issue for a while now. The session cookies are only set after i switch the tab etc.. and this is what i cameup with using getSession and refreshSession using supabase client as in the docs. Dont know if this is the right way but works for now(NB: only in non SRR mode)

 export default defineNuxtRouteMiddleware(async(to, _from) => {
  const supabase =  useSupabaseClient()
  let {data}= await supabase.auth.getSession()
if(!data.session){
  const { data, error } = await supabase.auth.refreshSession()
  let {user} = data 
  if(!user){
    return navigateTo('/login')
  }
}else{
  if(!data.session.user){
    return navigateTo('/login')
  }
}
  })

I havent really tested out if the refreshSession is actually required, and i think not, but i just put it there as a failsafe

Im using with ssr mode and setting cookies manually is mandatory thing until they fix this

anderslutzhoft commented 1 year ago

supabaseClient.auth.onAuthStateChange((_, _session) => { if(_session?.access_token) { const accessToken = useCookie('sb-access-token') const refreshToken = useCookie('sb-refresh-token') accessToken.value = _session?.access_token ?? null refreshToken.value = _session?.refresh_token ?? null } })

Hi @bayramorhan it seems like the onAuthStateChange() is not firing until I switch tabs, so unfortunately, it doesn't fix my issue :(

Are you running SSR?

anderslutzhoft commented 1 year ago

I found a fix that worked for me. I noticed that there was 4 cookies set after I switched tabs: 'my-access-token' 'my-refresh-token' 'sb-access-token' 'sb-refresh-token'

the values of access and refresh tokens where respectively the same. I got it to work by setting all 4 of them as per @bayramorhan s example AND setting the useSupabaseUser().value to the returned _session.user.

const myAccessToken = useCookie('my-access-token')
const myRefreshToken = useCookie('my-refresh-token')
const sbAccessToken = useCookie('sb-access-token')
const sbRefreshToken = useCookie('sb-refresh-token')

myAccessToken.value = _session?.access_token ?? null
myRefreshToken.value = _session?.refresh_token ?? null
sbAccessToken.value = _session?.access_token ?? null
sbRefreshToken.value = _session?.refresh_token ?? null

useSupabaseUser().value = _session.user

all of this done in the login_handler method.

heikopaiko commented 1 year ago

Any news on that topic?

bayramorhan commented 1 year ago

Any news on that topic?

I have managed to fix it with the solution above BUT and its a big but, it seems sometimes this solution is also not working.

heikopaiko commented 1 year ago

I got it working on localhost, but after deploying it to vercel it's back to tab-switching for it to work...

Edit: Even locally it's only working sometimes.

Flowko commented 1 year ago

so this might sound weird, but have you guys tried using useSupabaseAuthClient instead of useSupabaseClient cus that seems to resolve it for me at least, not sure if it'll break later or something, but for now that worked for me

heikopaiko commented 1 year ago

The way I got it working again was to manually update the gotrue-js package to the latest version.

bayramorhan commented 1 year ago

so this might sound weird, but have you guys tried using useSupabaseAuthClient instead of useSupabaseClient cus that seems to resolve it for me at least, not sure if it'll break later or something, but for now that worked for me

Using useSupabaseAuthClient resolved signOut issue but its not resolved session problem.

anderslutzhoft commented 1 year ago

I realized that this module is not even at a major release. It's 0.5.0. So I reverted back to using the native SupabaseJS, and it works as it should. Until they release a major update, I felt like it wouldn't be fair to assume full stability or production readiness.

heikopaiko commented 1 year ago

Can you share on how you did it? Thought about switching to native aswell.

anderslutzhoft commented 1 year ago

Can you share on how you did it? Thought about switching to native aswell.

Firstly I configured the whole app to CSR instead of SSR just to be sure. And then I just followed the instructions in the documentation and examples.

daniel-leadsfabriken commented 1 year ago

so this might sound weird, but have you guys tried using useSupabaseAuthClient instead of useSupabaseClient cus that seems to resolve it for me at least, not sure if it'll break later or something, but for now that worked for me

Dude, this made it for me. Changed it and login with password worked flawlessly. Unfortunately documentation is lacking.

rscorer commented 1 year ago

I have a reproducible case of this - using useSupabaseAuthClient helps partially but not completely.

See if my repo exhibits the problem you're all seeing? When I login (using signInWithPassword) the user is not in the composite useSupabaseUser but the auth session does actually contain the user.

https://github.com/rscorer/auth-demo

heikopaiko commented 1 year ago

It seems to me that the issue stems from the gotrue package. Once it's updated to the latest version, everything is working as intended.

rscorer commented 1 year ago

It seems to me that the issue stems from the gotrue package. Once it's updated to the latest version, everything is working as intended.

I am using the latest gotrue-js package - v2.11.0 - there is nothing later that I can see, and it is still exhibiting the bug.

jetlej commented 1 year ago

I have this issue as well. And this issue has been open for a month with no admin attention. @larbish can you please take a look?

MAXOUXAX commented 1 year ago

I'm using the useSupabaseAuthClient composable and still observing the same behavior, nothing updates until the window loses focus

larbish commented 1 year ago

I'm sorry guys but since I'm working hard on the beta opening of the Nuxt Studio and because I'm only using the supabase module for side projects that are all working well on production, I don't have much time to check issues if reproduction is missing. The demo is working as expected and deployed on Netlify. Please check it and if you can easily reproduce your wrong behaviour, create and share a repository to reproduce, I'll find a moment to help 🙏

MAXOUXAX commented 1 year ago

Hey @larbish, thanks for taking the time to address this ❤️

I believe this could be a reproduction of the issue:

Current behavior:

https://stackblitz.com/edit/nuxt-starter-tefz9j?file=pages/login.vue

⚠️ Warning: This doesn't work right out of the box for a few reasons

  1. Stackblitz seems to mess with cookies or whatever. While the session is retrieved correctly via the Supabase API, the useSupabaseUser() composable returns a ref to null at all times, even after refreshing the page or switching tabs, this should work locally though, since the Supabase API gets queried correctly.
  2. You need to define the SUPABASE_URL and SUPABASE_API_KEY environment variables in the .env file to your Supabase project credentials

EDIT: Something is happening that shouldn't: a SIGNED_IN event gets fired every time the tab gains focus (whether because you switched tabs or focused the window and were on the tab)

larbish commented 1 year ago

Hey @MAXOUXAX, thanks for the reproduction. The user returned by the useSupabaseUser composable is a reactive utility that only exists in the module scope but not in supabase itself. The module keeps it synchronised with the session. If you were using only supabase, you should do await authClient.auth.getUser() each time you would like to fetch the user (by doing so the reactivity is lost). I'm explaining that because since the user is not set by supabase itself, we'll receive the signInWithPassword response before the user is set in the chore of the module. To fix this behaviour you just need to watch the user in your login page/component. For your reproduction, something like this will work:

const supabase = useSupabaseAuthClient();
const user = useSupabaseUser()

watch(user, () => {
  if (user.value) {
    navigateTo('/authenticated')
  }
})

async function handleLoginForm() {
  const { error } = await supabase.auth.signInWithPassword({
    email: email.value,
    password: password.value,
  });

  if (error) {
    alert(error.message);
  }
}

I will update the documentation to explain it.

NB: Concerning the SIGNED_IN event getting fired on tab focus, I need to dive deeper to check what's going on. I've create an issue to keep track of it #163