Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 62 additions & 6 deletions packages/shared/src/components/auth/AuthOptionsInner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ import {
getNodeValue,
} from '../../lib/auth';
import {
getBetterAuthSocialUrl,
getBetterAuthErrorMessage,
getBetterAuthSocialRedirectData,
betterAuthSignInWithIdToken,
betterAuthSendVerificationOTP,
betterAuthVerifyEmailOTP,
Expand Down Expand Up @@ -164,6 +165,7 @@ function AuthOptionsInner({

const [isForgotPasswordReturn, setIsForgotPasswordReturn] = useState(false);
const [handleLoginCheck, setHandleLoginCheck] = useState<boolean>(null);
const socialErrorEventName = useRef(AuthEventNames.LoginError);
const [chosenProvider, setChosenProvider] = usePersistentState(
CHOSEN_PROVIDER_KEY,
null,
Expand Down Expand Up @@ -366,13 +368,32 @@ function AuthOptionsInner({
};

const handleLoginMessage = async (e?: MessageEvent) => {
const { data: boot } = await refetchBoot();
let boot;
try {
({ data: boot } = await refetchBoot());
} catch (error) {
logEvent({
event_name: socialErrorEventName.current,
extra: JSON.stringify({
error: getBetterAuthErrorMessage(
error,
'Failed to refresh Better Auth social auth state',
),
origin: 'betterauth social auth boot',
data:
typeof e?.data === 'object' ? JSON.stringify(e.data) : undefined,
}),
});
displayToast(labels.auth.error.generic);
return;
}

if (!boot.user || !('email' in boot.user)) {
logEvent({
event_name: AuthEventNames.SubmitSignUpFormError,
event_name: socialErrorEventName.current,
extra: JSON.stringify({
error: 'Could not find email on social registration',
error: 'Could not find email after social authentication',
origin: 'betterauth social auth boot',
data:
typeof e?.data === 'object' ? JSON.stringify(e.data) : undefined,
}),
Expand Down Expand Up @@ -404,6 +425,10 @@ function AuthOptionsInner({
};

const onProviderClick = async (provider: string, login = true) => {
const authErrorEventName = login
? AuthEventNames.LoginError
: AuthEventNames.RegistrationError;

logEvent({
event_name: 'click',
target_type: login
Expand All @@ -412,6 +437,7 @@ function AuthOptionsInner({
target_id: provider,
extra: JSON.stringify({ trigger }),
});
socialErrorEventName.current = authErrorEventName;

if (isBetterAuth) {
if (isNativeAuthSupported(provider)) {
Expand All @@ -425,6 +451,13 @@ function AuthOptionsInner({
nonce: res.nonce,
});
if (result.error) {
logEvent({
event_name: authErrorEventName,
extra: JSON.stringify({
error: result.error,
origin: 'betterauth native id token',
}),
});
return;
}
await setChosenProvider(provider);
Expand All @@ -433,20 +466,43 @@ function AuthOptionsInner({
}
const isIOSApp = isIOSNative();
onAuthStateUpdate?.({ isLoading: true });
if (!isIOSApp) {
windowPopup.current = window.open();
}
const callbackURL = `${webappUrl}callback?login=true`;
const socialUrl = await getBetterAuthSocialUrl(
const { url: socialUrl, error } = await getBetterAuthSocialRedirectData(
provider.toLowerCase(),
callbackURL,
);
if (!socialUrl) {
logEvent({
event_name: authErrorEventName,
extra: JSON.stringify({
error: error || 'Failed to get social login URL',
origin: 'betterauth social url',
}),
});
windowPopup.current?.close();
windowPopup.current = null;
onAuthStateUpdate?.({ isLoading: false });
return;
}
if (isIOSApp) {
window.location.href = socialUrl;
return;
}
windowPopup.current = window.open(socialUrl);
if (!windowPopup.current) {
logEvent({
event_name: authErrorEventName,
extra: JSON.stringify({
error: 'Failed to open social login window',
origin: 'betterauth social popup',
}),
});
onAuthStateUpdate?.({ isLoading: false });
return;
}
windowPopup.current.location.href = socialUrl;
await setChosenProvider(provider);
onAuthStateUpdate?.({ isLoading: true });
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import {
} from '../shared';
import type { FunnelStepSignup } from '../types/funnel';
import { useConsentCookie } from '../../../hooks/useCookieConsent';
import { useIsBetterAuth } from '../../../hooks/useIsBetterAuth';
import { isIOSNative } from '../../../lib/func';
import { GdprConsentKey } from '../../../hooks/useCookieBanner';
import Alert, { AlertType } from '../../../components/widgets/Alert';
Expand Down Expand Up @@ -141,7 +140,6 @@ function InnerFunnelRegistration({
}: FunnelStepSignup): ReactElement {
const router = useRouter();
const isTablet = useViewSize(ViewSize.Tablet);
const isBetterAuth = useIsBetterAuth();
const shouldRedirect = shouldRedirectAuth();
const windowPopup = useRef<Window | null>(null);
const { cookieExists } = useConsentCookie(GdprConsentKey.Marketing);
Expand All @@ -159,12 +157,11 @@ function InnerFunnelRegistration({
if (shouldRedirect) {
window.sessionStorage.setItem(AUTH_REDIRECT_KEY, window.location.href);
window.location.href = redirect;
} else if (isBetterAuth) {
if (isIOSNative()) {
window.location.href = redirect;
} else {
windowPopup.current = window.open(redirect);
}
return;
}

if (isIOSNative()) {
window.location.href = redirect;
} else if (windowPopup.current) {
windowPopup.current.location.href = redirect;
} else {
Expand All @@ -177,7 +174,10 @@ function InnerFunnelRegistration({
const subscriberEmail = router?.query?.subscribed;

const onRegister = (provider: SocialProvider) => {
if (!isBetterAuth && !isNativeAuthSupported(provider) && !shouldRedirect) {
const shouldUsePopup =
!shouldRedirect && !isNativeAuthSupported(provider) && !isIOSNative();

if (shouldUsePopup) {
windowPopup.current = window.open();
}
onSocialRegistration(provider);
Expand Down
117 changes: 101 additions & 16 deletions packages/shared/src/hooks/useLogin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ import {
import {
betterAuthSignIn,
betterAuthSignInWithIdToken,
getBetterAuthSocialUrl,
getBetterAuthErrorMessage,
getBetterAuthSocialRedirectData,
} from '../lib/betterAuth';
import { useIsBetterAuth } from './useIsBetterAuth';
import { useLogContext } from '../contexts/LogContext';
Expand Down Expand Up @@ -108,20 +109,48 @@ const useLogin = ({
logEvent({
event_name: AuthEventNames.LoginError,
extra: JSON.stringify({
error: labels.auth.error.invalidEmailOrPassword,
error: res.error,
displayedError: labels.auth.error.invalidEmailOrPassword,
origin: 'betterauth email login',
}),
});
setHint(labels.auth.error.invalidEmailOrPassword);
return;
}

const { data: boot } = await refetchBoot();
try {
const { data: boot } = await refetchBoot();

if (boot.user && !boot.user.shouldVerify) {
onUpdateSignBack(boot.user as LoggedUser, 'password');
}
if (!boot.user) {
logEvent({
event_name: AuthEventNames.LoginError,
extra: JSON.stringify({
error: 'Missing user after Better Auth email login',
origin: 'betterauth email login boot',
}),
});
setHint(labels.auth.error.generic);
return;
}

onSuccessfulLogin?.(boot?.user?.shouldVerify);
if (!boot.user.shouldVerify) {
onUpdateSignBack(boot.user as LoggedUser, 'password');
}

onSuccessfulLogin?.(boot.user.shouldVerify);
} catch (error) {
logEvent({
event_name: AuthEventNames.LoginError,
extra: JSON.stringify({
error: getBetterAuthErrorMessage(
error,
'Failed to refresh Better Auth login state',
),
origin: 'betterauth email login boot',
}),
});
setHint(labels.auth.error.generic);
}
},
});

Expand Down Expand Up @@ -195,27 +224,82 @@ const useLogin = ({
nonce: res.nonce,
});
if (result.error) {
logEvent({
event_name: AuthEventNames.LoginError,
extra: JSON.stringify({
error: result.error,
origin: 'betterauth native id token',
}),
});
return;
}
const { data: boot } = await refetchBoot();
if (boot.user) {
try {
const { data: boot } = await refetchBoot();
if (!boot.user) {
logEvent({
event_name: AuthEventNames.LoginError,
extra: JSON.stringify({
error: 'Missing user after Better Auth social login',
origin: 'betterauth native id token boot',
}),
});
displayToast(labels.auth.error.generic);
return;
}
onUpdateSignBack(
boot.user as LoggedUser,
provider as SignBackProvider,
);
} catch (error) {
logEvent({
event_name: AuthEventNames.LoginError,
extra: JSON.stringify({
error: getBetterAuthErrorMessage(
error,
'Failed to refresh Better Auth social login state',
),
origin: 'betterauth native id token boot',
}),
});
displayToast(labels.auth.error.generic);
}
return;
}
const isIOSApp = isIOSNative();
const socialPopup = isIOSApp ? null : window.open();
const callbackURL = `${webappUrl}callback?login=true`;
const socialUrl = await getBetterAuthSocialUrl(provider, callbackURL);
if (socialUrl) {
if (isIOSApp) {
window.location.href = socialUrl;
} else {
window.open(socialUrl);
}
const { url: socialUrl, error } = await getBetterAuthSocialRedirectData(
provider,
callbackURL,
);
if (!socialUrl) {
logEvent({
event_name: AuthEventNames.LoginError,
extra: JSON.stringify({
error: error || 'Failed to get social login URL',
origin: 'betterauth social url',
}),
});
socialPopup?.close();
displayToast(labels.auth.error.generic);
return;
}
if (isIOSApp) {
window.location.href = socialUrl;
return;
}
if (socialPopup) {
socialPopup.location.href = socialUrl;
return;
}
logEvent({
event_name: AuthEventNames.LoginError,
extra: JSON.stringify({
error: 'Failed to open social login window',
origin: 'betterauth social popup',
}),
});
displayToast(labels.auth.error.generic);
return;
}

Expand All @@ -236,6 +320,7 @@ const useLogin = ({
isBetterAuth,
displayToast,
login?.ui,
logEvent,
onSocialLogin,
refetchBoot,
onUpdateSignBack,
Expand Down
Loading
Loading