fix(oauth): add callback error page for google oauth flow
Some checks failed
Frontend CI/CD / build (push) Has been cancelled
Frontend CI/CD / deploy (push) Has been cancelled

This commit is contained in:
2026-05-22 00:59:19 +03:30
parent dbc0ebb118
commit 065360b7a8
3 changed files with 33 additions and 1 deletions

View File

@@ -123,8 +123,12 @@ export const en = {
mobileClaimDescription: (mobile: string) => mobileClaimDescription: (mobile: string) =>
`A mobile-only account with ${mobile} already exists. Verify the code sent to that number to attach Google and keep that account.`, `A mobile-only account with ${mobile} already exists. Verify the code sent to that number to attach Google and keep that account.`,
errorTitle: "Google sign in could not be completed", errorTitle: "Google sign in could not be completed",
cancelled: "Google sign in was cancelled before it could be completed.",
missingFlow: "The Google sign-in flow is missing or has expired.", missingFlow: "The Google sign-in flow is missing or has expired.",
loadFailed: "We could not load your Google sign-in state.", loadFailed: "We could not load your Google sign-in state.",
callbackFailed: "We could not complete Google sign in. Please try again.",
tokenExchangeFailed: "Google sign in is temporarily unavailable. Please try again in a few minutes.",
profileLookupFailed: "We could not load your Google profile. Please try again.",
completeFailed: "We could not finish your Google account setup.", completeFailed: "We could not finish your Google account setup.",
claimOtpSent: "Verification code sent successfully.", claimOtpSent: "Verification code sent successfully.",
googleAccount: "Google account", googleAccount: "Google account",

View File

@@ -123,8 +123,12 @@ export const fa = {
mobileClaimDescription: (mobile: string) => mobileClaimDescription: (mobile: string) =>
`حسابی بدون ایمیل با شماره ${mobile} از قبل وجود دارد. کد ارسال‌شده به این شماره را وارد کنید تا گوگل به همان حساب متصل شود.`, `حسابی بدون ایمیل با شماره ${mobile} از قبل وجود دارد. کد ارسال‌شده به این شماره را وارد کنید تا گوگل به همان حساب متصل شود.`,
errorTitle: "ورود با گوگل کامل نشد", errorTitle: "ورود با گوگل کامل نشد",
cancelled: "فرآیند ورود با گوگل قبل از تکمیل لغو شد.",
missingFlow: "جریان ورود با گوگل پیدا نشد یا منقضی شده است.", missingFlow: "جریان ورود با گوگل پیدا نشد یا منقضی شده است.",
loadFailed: "بارگذاری وضعیت ورود با گوگل انجام نشد.", loadFailed: "بارگذاری وضعیت ورود با گوگل انجام نشد.",
callbackFailed: "تکمیل ورود با گوگل انجام نشد. لطفاً دوباره تلاش کنید.",
tokenExchangeFailed: "ورود با گوگل موقتاً در دسترس نیست. چند دقیقه دیگر دوباره تلاش کنید.",
profileLookupFailed: "دریافت اطلاعات حساب گوگل انجام نشد. لطفاً دوباره تلاش کنید.",
completeFailed: "تکمیل ساخت حساب با گوگل انجام نشد.", completeFailed: "تکمیل ساخت حساب با گوگل انجام نشد.",
claimOtpSent: "کد تایید با موفقیت ارسال شد.", claimOtpSent: "کد تایید با موفقیت ارسال شد.",
googleAccount: "حساب گوگل", googleAccount: "حساب گوگل",

View File

@@ -34,6 +34,8 @@ export default function GoogleAuthCallback() {
const isRtl = lang === "fa"; const isRtl = lang === "fa";
const flow = searchParams.get("flow") ?? ""; const flow = searchParams.get("flow") ?? "";
const callbackErrorCode = searchParams.get("error") ?? "";
const callbackErrorDescription = searchParams.get("error_description") ?? "";
const [step, setStep] = useState<GoogleStep>("loading"); const [step, setStep] = useState<GoogleStep>("loading");
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@@ -50,6 +52,22 @@ export default function GoogleAuthCallback() {
otpVerify: 0, otpVerify: 0,
}); });
const resolveCallbackErrorMessage = () => {
if (callbackErrorCode === "access_denied") {
return t.login.google.cancelled;
}
if (callbackErrorDescription) {
if (callbackErrorDescription === "Google token exchange failed.") {
return t.login.google.tokenExchangeFailed;
}
if (callbackErrorDescription === "Google user profile lookup failed.") {
return t.login.google.profileLookupFailed;
}
return callbackErrorDescription;
}
return t.login.google.callbackFailed;
};
useEffect(() => { useEffect(() => {
if (!Object.values(cooldowns).some((value) => value > 0)) { if (!Object.values(cooldowns).some((value) => value > 0)) {
return; return;
@@ -138,6 +156,12 @@ export default function GoogleAuthCallback() {
}; };
useEffect(() => { useEffect(() => {
if (callbackErrorCode) {
setErrorMessage(resolveCallbackErrorMessage());
setStep("error");
return;
}
if (!flow) { if (!flow) {
setErrorMessage(t.login.google.missingFlow); setErrorMessage(t.login.google.missingFlow);
setStep("error"); setStep("error");
@@ -170,7 +194,7 @@ export default function GoogleAuthCallback() {
return () => { return () => {
cancelled = true; cancelled = true;
}; };
}, [flow]); }, [callbackErrorCode, callbackErrorDescription, flow, lang]);
const handleCompleteSignup = async (event: React.FormEvent) => { const handleCompleteSignup = async (event: React.FormEvent) => {
event.preventDefault(); event.preventDefault();