fix(auth): complete Google OAuth after SDK boot (was stuck on ?code=…#identify)

The OAuth-return effect ran on mount before AppShell finished booting, so
completeOAuthLogin no-oped (sdk.auth undefined → null) and fell back to identify,
never retrying. Gate it on useAppShell().ready so it runs once auth is up, and
strip ?code= from the URL on success.
This commit is contained in:
tanweer919
2026-07-13 01:31:37 +05:30
parent 74caae0710
commit 6e1a895e7e
+15 -3
View File
@@ -9,7 +9,7 @@ import {
PasswordStrength, PasswordStrength,
} from "./bits"; } from "./bits";
import { lookupAccount, maskEmail, type Account } from "./data"; import { lookupAccount, maskEmail, type Account } from "./data";
import { useAuth } from "@abe-kap/appshell-sdk/react"; import { useAuth, useAppShell } from "@abe-kap/appshell-sdk/react";
import { isShellConfigured } from "@/lib/appshell"; import { isShellConfigured } from "@/lib/appshell";
// Map the portal's social button ids to Supabase OAuth provider ids. // Map the portal's social button ids to Supabase OAuth provider ids.
@@ -25,6 +25,7 @@ const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
export function LoginFlow() { export function LoginFlow() {
const router = useRouter(); const router = useRouter();
const { login, loginWithOAuth, completeOAuthLogin } = useAuth(); const { login, loginWithOAuth, completeOAuthLogin } = useAuth();
const { ready } = useAppShell();
const [step, setStep] = useState<Step>("identify"); const [step, setStep] = useState<Step>("identify");
const [email, setEmail] = useState(""); const [email, setEmail] = useState("");
const [account, setAccount] = useState<Account | null>(null); const [account, setAccount] = useState<Account | null>(null);
@@ -70,11 +71,22 @@ export function LoginFlow() {
if (!isShellConfigured()) return; if (!isShellConfigured()) return;
const code = new URLSearchParams(window.location.search).get("code"); const code = new URLSearchParams(window.location.search).get("code");
if (!code) return; if (!code) return;
// Wait until the SDK has booted — completeOAuthLogin no-ops (returns null) if
// sdk.auth isn't ready yet, and this effect only re-runs when `ready` flips.
if (!ready) { setStep("connecting"); return; }
setStep("connecting"); setStep("connecting");
completeOAuthLogin(code) completeOAuthLogin(code)
.then((ace) => { if (ace) router.replace("/dashboard"); else replace("identify"); }) .then((ace) => {
if (ace) {
// Clear the ?code=… from the URL, then enter the app.
window.history.replaceState({}, "", "/portal/login");
router.replace("/dashboard");
} else {
replace("identify");
}
})
.catch(() => { setFlash("Sign-in with that provider didn't complete. Try again."); replace("identify"); }); .catch(() => { setFlash("Sign-in with that provider didn't complete. Try again."); replace("identify"); });
}, [completeOAuthLogin, router]); }, [ready, completeOAuthLogin, router]);
/* ---- auth resolution ---- */ /* ---- auth resolution ---- */
function afterAuth(factor: "password" | "passkey" | "otp" | "totp" | "push" | "social") { function afterAuth(factor: "password" | "passkey" | "otp" | "totp" | "push" | "social") {