Skip to content

Commit 28c3f46

Browse files
authored
fix: redirect errors (#5842)
1 parent e21034c commit 28c3f46

File tree

3 files changed

+52
-1
lines changed

3 files changed

+52
-1
lines changed

packages/shared/src/components/auth/AuthOptionsInner.tsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,23 @@ function AuthOptionsInner({
196196
const [isRegistration, setIsRegistration] = useState(false);
197197
const [isSocialAuthLoading, setIsSocialAuthLoading] = useState(false);
198198
const windowPopup = useRef<Window | null>(null);
199+
const popupCheckIntervalRef = useRef<ReturnType<typeof setInterval> | null>(
200+
null,
201+
);
202+
const authFlowCompletedRef = useRef(false);
203+
204+
const clearPopupCheck = () => {
205+
if (popupCheckIntervalRef.current) {
206+
clearInterval(popupCheckIntervalRef.current);
207+
popupCheckIntervalRef.current = null;
208+
}
209+
};
210+
211+
useEffect(() => {
212+
return () => {
213+
clearPopupCheck();
214+
};
215+
}, []);
199216

200217
const checkForOnboardedUser = async (data: LoggedUser) => {
201218
onAuthStateUpdate({ isLoading: true });
@@ -383,6 +400,21 @@ function AuthOptionsInner({
383400
};
384401

385402
const handleLoginMessage = async (e?: MessageEvent) => {
403+
authFlowCompletedRef.current = true;
404+
clearPopupCheck();
405+
const popup = windowPopup.current;
406+
windowPopup.current = null;
407+
if (popup && !popup.closed) {
408+
popup.close();
409+
// Retry after a short delay — some browsers defer the close when the
410+
// popup is still settling after a redirect chain.
411+
setTimeout(() => {
412+
if (!popup.closed) {
413+
popup.close();
414+
}
415+
}, 300);
416+
}
417+
386418
const callbackError = getSocialAuthCallbackError(e?.data);
387419
if (callbackError) {
388420
setIsSocialAuthLoading(false);
@@ -556,6 +588,21 @@ function AuthOptionsInner({
556588
windowPopup.current.location.href = socialUrl;
557589
await setChosenProvider(provider);
558590
onAuthStateUpdate?.({ isLoading: true });
591+
592+
authFlowCompletedRef.current = false;
593+
clearPopupCheck();
594+
const popup = windowPopup.current;
595+
popupCheckIntervalRef.current = setInterval(() => {
596+
if (!popup || popup.closed) {
597+
clearPopupCheck();
598+
if (!authFlowCompletedRef.current) {
599+
setIsSocialAuthLoading(false);
600+
onAuthStateUpdate?.({ isLoading: false });
601+
displayToast(SOCIAL_AUTH_RETRY_MESSAGE);
602+
}
603+
windowPopup.current = null;
604+
}
605+
}, 500);
559606
};
560607

561608
const onProviderMessage = async (e: MessageEvent) => {

packages/shared/src/lib/betterAuth.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ const getBetterAuthSocialRedirect = async (
164164
{
165165
provider,
166166
callbackURL: absoluteCallbackURL,
167+
errorCallbackURL: absoluteCallbackURL,
167168
disableRedirect: true,
168169
...(additionalData && { additionalData }),
169170
},

packages/webapp/pages/callback.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,10 @@ function CallbackPage(): ReactElement | null {
7575
// while still allowing a script-opened tab to close itself. Try the
7676
// close first and only fall back to a redirect if we know there is no
7777
// opener to return to.
78-
if (!window.opener) {
78+
// Skip the redirect when there are error params — the opener handles
79+
// closing the popup and showing the error toast.
80+
const hasError = urlSearchParams.has('error');
81+
if (!window.opener && !hasError) {
7982
setTimeout(() => {
8083
window.location.replace('/onboarding');
8184
}, 300);

0 commit comments

Comments
 (0)