Call auth.onAuthStateChange at least once when listener is registered.
Feature request
Call auth.onAuthStateChange() at least once when registering the listener.
Is your feature request related to a problem? Please describe.
When getting the current user, I have to first get the user using auth.user(), then add a listener using auth.onAuthStateChange() and implement the same code there.
Describe the solution you'd like
I feel like it would be better if auth.onAuthStateChange() is called at least once when registering the listener, this removes unnecessary duplicate or spaghetti code. Additionally, this is also how firebase does it: https://firebase.google.com/docs/reference/android/com/google/firebase/auth/FirebaseAuth.AuthStateListener
Describe alternatives you've considered
There is a solution as mentioned above, but doesn't result in the cleanest code.
Additional context
None.
Wrote this workaround for myself:
export const onAuthStateChange: SupabaseClient['auth']['onAuthStateChange'] = (
callback
) => {
// Until https://github.com/supabase/gotrue-js/issues/313 is resolved
// Fire the callback once with the user session if authenticated.
const session = supabase.auth.session();
if (session) {
const event: AuthChangeEvent = 'SIGNED_IN';
callback(event, session);
}
return supabase.auth.onAuthStateChange(callback);
};
@supabase/auth-team Assigning it to the PIC of the team @hf to take care of this.
V2 Has been released in RC and this issue is still present. And with V2 it now calls for even more advanced async handling due to sync auth.user() & auth.session() being removed. I can recall many instances of users opening issues on this in V1 and personally think it should be highlighted as almost every Firebase dev migrating is used to the easy handling of getting the user object on first load.
Regardless, here is the V2 code attempting to fix this.
import type { SupabaseClient } from "@supabase/supabase-js";
export const onAuthStateChange: SupabaseClient["auth"]["onAuthStateChange"] = (
callback
) => {
// Until https://github.com/supabase/gotrue-js/issues/313 is resolved
// Fire the callback once with the user session if authenticated.
supabase.auth.getSession().then(({ data, error }) => {
if (!error && data.session) {
callback("SIGNED_IN", data.session);
}
});
return supabase.auth.onAuthStateChange(callback);
};
hey @sannajammeh and @Xzoky174, can you guys please explain why it is necessary for the callback to be fired when the listener is registered aside from remaining compatible with firebase?
If the reasoning is for easy handling of getting the user object on first load, you can just use getSession in supabase-js v2 to get the current user. It doesn't seem necessary for it to be invoke when onAuthStateChange is called. Maybe i'm missing something obvious here 😅
hey @sannajammeh and @Xzoky174, can you guys please explain why it is necessary for the callback to be fired when the listener is registered aside from remaining compatible with firebase?
If the reasoning is for easy handling of getting the user object on first load, you can just use
getSessionin supabase-js v2 to get the current user. It doesn't seem necessary for it to be invoke whenonAuthStateChangeis called. Maybe i'm missing something obvious here 😅
Firstly it's the point of Firebase migrations. onAuthStateChange always invokes with the the available auth object.
Secondly it's the ease of use. When we invoke with the object we are also able to provide a single source of truth to any global user store in our codebase. getSession fires once, onAuthStateChange should logically fire every time the auth object changes, which by extension includes when it's loaded as it goes from no-auth to auth.
Then it's the duplicated logic needed when onAuthStateChange is not invoking:
- User fetching
- Post auth validation
- Setting JWT cookie server side
- Fetching user related data (once)
All this could've been done in a few lines if it fires with the user on load. However we now have to either move this logic outside and have these points react to data changes or duplicate this logic first getSession then inside onAuthStateChange.
It's certainly not a problem at all when you only do simple things like fetching the user. Even then it's logical to have it invoke as the auth state literally changes.
I'll see if I can look through my commit history on one of my projects. I recall writing my onAuthStateChange wrapper saved 40-50 lines of duplicate logic. Either way it's up to you guys if you want to implement it. We'll keep writing wrappers 😅.
Edit: there is one last point which was why I ended up wrapping it the first time. React's reactivity. Supabase uses redirect based auth. Therefore if I set the user state during getSession & also do it inside onAuthStateChange and the user logs in and is redirected back, I now have 2 auth objects which are the same but have different reference. AKA 2 state updates. React doesn't do deep equality checks, so if I send a POST request to set an auth cookie I now end up with 2 requests.
:tada: This issue has been resolved in version 2.16.0 :tada:
The release is available on:
Your semantic-release bot :package::rocket: