user from useUser are sometimes null when coming back from redirect after third party sign in
Hi Supabase community.
I have found that sometimes when successfully signing in with third party providers (Facebook, Twitter and Google) the user returned from useUser hook is null even though the user on server side is signed in (checked logs + fragment with tokens is returned correctly). It happens only sometimes when signing in the first time in a new browser / tab session.
It happens like this.
- Build app
- Call signIn with facebook provider (or other provider)
- Redirects to provider link
- Successful sign in at provider
- Redirects back to app (this is where useUser returns null user)
As the fragment with tokens are returned correctly a temporary fix is getting it and signing the user in manually like so: App (pages/index.tsx)
export default function App() {
const { user, isLoading } = useUser();
const router = useRouter();
const isSignedIn = user;
let isWaitingForSignIn = false;
let refreshToken: string;
if (!isSignedIn) {
/**
* Get fragment params. Will only exist if bug happens in supabase helpers -
* causing the successful signin with third party to not be registered -
* here on client side after re-direct from provider.
*/
const fragmentParams = getFragmentParams(router.asPath);
refreshToken = fragmentParams.refresh_token;
if (refreshToken) {
/*
Function to manually sign user in with refresh token from fragment.
*/
const signUserInWithRefreshToken = () =>
authService.signIn({
refreshToken,
});
/*
* To avoid sign in page flicker while waiting for sign in.
* Page will re-render after successful sign in and isWaitingForSignIn -
* will be set to false while isSignedIn will be true
*/
isWaitingForSignIn = true;
signUserInWithRefreshToken();
}
}
if (isLoading || isWaitingForSignIn) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return <AuthLoadingScreen />;
}
/* is signed in */
if (isSignedIn) return <SignedInPage />;
return <SigninPage />;
}
getFragmentParams.ts
export const getFragmentParams = (asPath: string) => {
const urlSearchParams = new URLSearchParams(asPath.split('#')[1]);
const fragmentParams = Object.fromEntries(urlSearchParams.entries());
return fragmentParams;
};
Project info:
- Expo sdk 44
- Next js 11.0.1
- Supabase js 1.30.7
- Supabase auth helpers 1.2.3
Same here :(
The issue seems to be this one: https://github.com/supabase/supabase/discussions/6080
Can you upgrade to the latest version and see if that resolves it?
I'm experiencing this issue with the latest version. I have a hook like such:
export const RequireAuth = (callback = () => {}) => {
const { user, isLoading } = useUser();
const router = useRouter();
useEffect(() => {
if (!isLoading) {
if (user) {
callback();
} else {
router.replace("/login");
}
}
}, [isLoading, user, router]);
};
When I include this hook in a page that is redirected to after signup via magic link, it redirects the user despite being logged in.
I'm experiencing a similar issue as well using magic link sign in. The magic link we send users points to a page protected by the withPageAuth helper - the helper redirects the user before the user is logged in.
As it stands today, you will need to set the redirect URL to be a client-side route, e.g. your sign-in page, and then have a hook that monitors the user object and redirects to the desired page, e.g. see this example: https://github.com/vercel/nextjs-subscription-payments/blob/main/pages/signin.tsx#L58-L62
const { user } = useUser();
useEffect(() => {
if (user) {
router.replace('/account');
}
}, [user]);
That's because the OAuth sign-in state is currently communicated via a URL fragment and therefore can't be accessed server-side.