supabase / auth-js

An isomorphic Javascript library for Supabase Auth.
MIT License
358 stars 161 forks source link

signIn / signOut not working properly #345

Closed matheustav closed 2 years ago

matheustav commented 2 years ago

Bug report

Describe the bug

Hi! I think signOut method is not properly destroying the session until the page is refreshed.

To Reproduce

  1. Sign in
  2. Get data from database related to user
  3. Sign out
  4. Sign in again with another user
  5. Try to get user-related data from db again

I'm using this code to test:

// Login
setTimeout(
    async () => console.log( await this.$supa.auth.signIn( { email: 'user111@test.com', password: 'foo123' } ) ),
    1000
);

// Profile
setTimeout(
    async () => console.log( await this.$supa.from( 'profiles' ).select().single() ),
    2000
);

// Logout
setTimeout(
    async () => console.log( await this.$supa.auth.signOut() ),
    3000
);

// Login again
setTimeout(
    async () => console.log( await this.$supa.auth.signIn( { email: 'user222@test.com', password: 'bar123' } ) ),
    4000
);

// Profile
setTimeout(
    async () => console.log( await this.$supa.from( 'profiles' ).select().single() ),
    5000
);

The problem is that both select profile requests always returns the same profile.

  1. If I logged In with user1 first, then both profiles will be from user1.
  2. If I change the code, switching the signIn order (user2 before), then both profiles will be from user2 now.

Expected behavior

To each select get only the profile of the authenticated user.

Screenshots

My RLS: 2022-03-24_16-12-29

Testing with user1 before: 2022-03-24_16-03-39

Now switching the signIn credentials: 2022-03-24_16-06-44

System information

kangmingtay commented 2 years ago

hey @matheustav, i can't seem to reproduce this:

I made some adjustments to the code you sent so it's easier for me to debug

async function main() {
  // Login
  setTimeout(
    async () => {
      console.log("Sign in with user111")
      const { user } = await supabase.auth.signIn({ email: 'user111@test.com', password: 'foo123' })
      console.log(user.id)
    },
    1000
  );

  // Profile
  setTimeout(
    async () => {
      console.log("Get user111's profile.id")
      const { data, error } = await supabase.from('profiles').select().single()
      console.log(data.id, error)
    },
    2000
  );

  // Logout
  setTimeout(
    async () => {
      console.log("Logout")
      console.log(await supabase.auth.signOut())
    },
    3000
  );

  // Login again
  setTimeout(
    async () => {
      console.log("Sign in with user222")
      const { user } = await supabase.auth.signIn({ email: 'user222@test.com', password: 'foo123' })
      console.log(user.id)
    },
    4000
  );

  // Profile
  setTimeout(
    async () => {
      console.log("Get user222's profile.id")
      const { data, error } = await supabase.from('profiles').select().single()
      console.log(data.id, error)
    },
    5000
  );

}

main()

Can you please try to see if the issue is fixed already? Else, feel free to reopen this issue and we can discuss

walkerdustin commented 1 year ago

I currently have a similar problem. Where after sign out, still the old user persists somehow.#

My auth is only on the clientside. I use sveltekit (as a static site generator)

after signOut() there is still the sb-refresh-token cookie and the sb-access-token cookie with the jwt thus, supabase.auth.getUser() still gets me the user

so user does not get logged out.

what helped me is to reload the page after the signout()

aka not use the linking and goto() function of my framework but rather use browser function

window.location.href = '/loggedOut';

steffenstolze commented 1 year ago

Why has this been closed? :)

I have three Nuxt v3 projects (in SPA mode) with Supabase that stopped working regarding reliable signing / signout.

we have a SignIn function

const handleSignIn = async () => {
    console.log('pages/auth/signin.vue - handleSignIn');
    loading.value = true;
    try {
        const { error } = await supabase.auth.signInWithPassword({
            email: signInForm.email,
            password: signInForm.password,
        });
        if (error) throw error;
        //a successful signIn attempt will update the supabaseUser and trigger the watcher below
    } catch (error) {
        console.error('Error while signing in', error);
        signInError.value = true;
        loading.value = false;
    }
};

and a watcher on the supabaseUser ref that is not triggered reliable lately (page refresh sometimes works)

const supabaseUser = useSupabaseUser();

watch(supabaseUser, async () => {
    console.log('DEBUG: Supabase user changed')
    //when this object receives an update, it's the logged in supabase user.
    const profile = await GetUserProfile(supabaseUser.value.id);
    userCookie.value = {
        id_user_profiles: supabaseUser.value.id,
        firstname: profile.firstname,
        lastname: profile.lastname,
        email: profile.email,
        preferred_language: profile.preferred_language || userLanguage.value || 'en',
        company_name: profile.company_name,
    };
    locale.value = profile.preferred_language;
    return navigateTo('/dashboard');
});

so.. SignIn doesn't always work.

for SignOut we just trigger the Supabase API

const handleSignout = async () => {
    try {
        loading.value = true;
        const { error } = await supabase.auth.signOut();
        if (error) {
            signedOutError.value = error;
            throw error;
        }
        signedOut.value = true;
    } catch (error) {
        console.error('Error while signing out', error);
    } finally {
        loading.value = false;
    }
};

The browser gets a correct response with set-cookie header and should remove the cookie accordingly:

image

but.. even after waiting some seconds and refreshing the cookies:

image

which means that I can change routes to /dashboard and would still be able to interact with the application.

Strange thing is.. this all worked reliably in the fast.

[EDIT] I just stumbled over a new composable useSupabaseAuthClient from Nuxt Supabase which seems to solve the SignOut problem for now. I did not have a change to check what's going on under the hood. But I'd assume that calling supabaseClient.signOut() should be enough to really sign out a user, shouldn't it?

dittrm commented 1 year ago

Hm, I use const client = useSupabaseAuthClient() to sign in and out. And it works - so far - as expected.

signIn

const client = useSupabaseAuthClient()
const signIn = async () => {
   const { data, error } = await client.auth.signInWithPassword({
      email: email.value,
      password: password.value
   })
})

signOut

const client = useSupabaseAuthClient()
const user = useSupabaseUser()
const signOut= async () => {
   try {
      const { error } = await client.auth.signOut()
      if (error) throw error
      user.value = null
   } catch (error) {
      alert(error.message)
   }
}

Does this work for you as well?

matheustav commented 1 year ago

Hi! Thanks for all responses, but I think the problem is now solved (20 days ago), based on these PRs: https://github.com/supabase/gotrue/pull/830 https://github.com/supabase/gotrue-js/pull/541

I can't confirm if it's really solved though, because I'm no longer using Supabase while some features I needed are not properly developed, tested and available for all users (like custom domains).

justusbluemer commented 1 year ago

The thing that solved it for me was using useSupabaseAuthClient rather than useSupabaseClient:

const supabase = useSupabaseAuthClient();

No idea why though ;)