Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Global supabase.auth.signOut() doesn't fire the "SIGNED_OUT" event for onAuthStateChange in other instances where a user is logged in #902

Open
2 tasks done
belle-chang opened this issue May 7, 2024 · 7 comments
Labels
bug Something isn't working

Comments

@belle-chang
Copy link

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

Whenever I call supabase.auth.signOut(), onAuthStateChange only fires a "SIGNED_OUT" event for the current device I'm on; not for any other devices the user is logged into. This is causing a weird in-between state where the user isn't authenticated on a device, and there isn't a listener to know when to trigger clean up, which is causing my authenticated API calls to fail.

Just to note, I'm calling supabase.auth.signOut() from the client, using a supabase client that's been created according to the React native docs:

export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
  auth: {
    storage: AsyncStorage,
    autoRefreshToken: true,
    persistSession: true,
    detectSessionInUrl: false,
  },
})

From the supabase docs:

SIGNED_OUT
Emitted when the user signs out. This can be after:
- A call to supabase.auth.signOut().
- After the user's session has expired for any reason:
- User has signed out on another device.
- The session has reached its timebox limit or inactivity timeout.
- User has signed in on another device with single session per user enabled.
Check the [User Sessions](https://supabase.com/docs/guides/auth/sessions) docs for more information.
- Use this to clean up any local storage your application has associated with the user.

To Reproduce

Have a user signed into two devices, call a global signOut() on one of them.

Expected behavior

SIGNED_OUT should fire for onAuthStateChange on all instances of where a user is logged in.

Screenshots

If applicable, add screenshots to help explain your problem.

System information

  • OS: [e.g. macOS, Windows]
  • Browser (if applies) [e.g. chrome, safari]
  • Version of supabase-js: [e.g. 6.0.2]
  • Version of Node.js: [e.g. 10.10.0]

Additional context

Add any other context about the problem here.

@belle-chang belle-chang added the bug Something isn't working label May 7, 2024
@belle-chang
Copy link
Author

belle-chang commented May 7, 2024

To add more context, we are running into an issue when there's a global log out, we're still seeing that the user is authenticated on the client (seems to be the correct behavior from Sign out a user documentation), but on our server, when we call await supabase.auth.getUser(token); to get relevant data, we get this error:

message: "Session from session_id claim in JWT does not exist"
name: "AuthApiError"
stack: "AuthApiError: Session from session_id claim in JWT does not exist"
status: 403

What is the best way to handle this, in the case of a global log out? We were planning on using the onAuthStateChange to handle this, but it seems like it isn't working properly.

Sign out a user
Inside a browser context, signOut() will remove the logged in user from the browser session and log them out - removing all items from localstorage and then trigger a "SIGNED_OUT" event.

In order to use the signOut() method, the user needs to be signed in first.
By default, signOut() uses the global scope, which signs out all other sessions that the user is logged into as well.
Since Supabase Auth uses JWTs for authentication, the access token JWT will be valid until it's expired. When the user signs out, Supabase revokes the refresh token and deletes the JWT from the client-side. This does not revoke the JWT and it will still be valid until it expires.

@j4w8n
Copy link
Contributor

j4w8n commented May 7, 2024

@belle-chang, can you clarify a couple of things?

we're still seeing that the user is authenticated on the client

Is this on the browser where the logout happened, or the the other?

on our server, when we call await supabase.auth.getUser(token); to get relevant data, we get [the] error

Which browser session is this token from?

@belle-chang
Copy link
Author

This is happening in a React Native app, so say I have 2 devices where a user is logged in. If a user does a global log out on device A, the user is still seen as authenticated on device B when you call supabase.auth.getSession() -- which seems to be expected behavior due to Supabase signOut documentation. However, when calling supabase.auth.getUser() in our backend (no local storage/it's not recommended as a source of trusted data on the server), which we use to authenticate each API call, it's throwing that error.

The token is passed from our front end in an Authorization bearer header to the backend, where it's used in the supabase.auth.getUser() to check if the user is authenticated before executing an api call

@j4w8n
Copy link
Contributor

j4w8n commented May 8, 2024

Ok, I believe I understand what you're saying.

So when the device/app with a still-logged-in-session(at least locally) does something, the error is thrown when calling supabase.auth.getUser(access_token) on the backend.

This makes sense, since it's a global signout. Supabase would likely remove both sessions in the auth.sessions table - even though the access token from said device would still be good for the rest of its lifetime.

@kangmingtay
Copy link
Member

Session from session_id claim in JWT does not exist

@belle-chang you can fix this issue by upgrading to the latest supabase-js version - for context, we fixed it in this PR (#894), basically, signOut should always remove the existing session from the client regardless of any 4xx error because the user could've been deleted by an admin.

on the main topic of the SIGNED_OUT event not being broadcast to other devices:

currently, onAuthStateChange only emits the events to the listeners scoped to the instance of the supabase client class. when you're on a separate device, that is using a different instance of the supabase client so it won't receive any of these events.

apologies for the confusion in the docs - we'll update it so it's clear next time.

@soeren-krueger
Copy link

Session from session_id claim in JWT does not exist

@belle-chang you can fix this issue by upgrading to the latest supabase-js version - for context, we fixed it in this PR (#894), basically, signOut should always remove the existing session from the client regardless of any 4xx error because the user could've been deleted by an admin.

This unfortunately still doesn't solve the described problem as the session is not removed on the other device, but only from the device calling signOut.
Working around this right now by returning some error code from the backend if the session is no longer valid (getUser() error) and then signing the user out manually in the client.

@anggaaryas
Copy link

can we make this behavior like listening realtime table?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

5 participants