nuxt-modules / supabase

Supabase module for Nuxt.

Home Page:https://supabase.nuxtjs.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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

anderslutzhoft opened this issue · comments

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!

commented

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

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.

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
      }
    })

@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!

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.

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

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

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?

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.

Any news on that topic?

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.

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.

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

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

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.

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.

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

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.

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.

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

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.

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.

commented

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?

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

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 🙏

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

I believe this could be a reproduction of the issue:

  • Login page that redirects you to another route once logged in (Supabase Auth via email/password)
  • Auth middleware which is blocking access to the /authenticated route for users that are not logged in.

Current behavior:

  • When logging in, your tokens are defined in your browser cookies
  • Once you get redirected to the /authenticated route, the middleware checks your access
  • The useSupabaseUser() composable is not defined right after the login, which leads to an abort of the navigation

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)

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