From 0e30f1790cd3a1717dcb55ae137700de9bb0dfcb Mon Sep 17 00:00:00 2001 From: soryu Date: Thu, 5 Mar 2026 16:05:01 +0000 Subject: fix: restore code entry in daemon reauth flow The previous commit removed the manual auth code input, expecting OAuth to complete automatically via token auto-detection. This restores the code entry field as the primary path while keeping token auto-detection as a parallel fallback. Co-Authored-By: Claude Opus 4.6 --- makima/frontend/src/routes/daemons.tsx | 134 ++++++++++++++++++++++----------- 1 file changed, 91 insertions(+), 43 deletions(-) (limited to 'makima/frontend/src') diff --git a/makima/frontend/src/routes/daemons.tsx b/makima/frontend/src/routes/daemons.tsx index aa48deb..a13c6de 100644 --- a/makima/frontend/src/routes/daemons.tsx +++ b/makima/frontend/src/routes/daemons.tsx @@ -6,6 +6,7 @@ import { listDaemons, restartDaemon, triggerDaemonReauth, + submitDaemonAuthCode, getDaemonReauthStatus, type Daemon, type DaemonListResponse, @@ -42,7 +43,7 @@ function ErrorAlert({ children }: { children: React.ReactNode }) { type ReauthState = | { phase: "initiating" } | { phase: "url_ready"; loginUrl: string; requestId: string } - | { phase: "waiting_for_auth"; loginUrl: string; requestId: string } + | { phase: "submitting"; requestId: string } | { phase: "success" } | { phase: "error"; message: string }; @@ -54,6 +55,7 @@ function ReauthModal({ onClose: () => void; }) { const [state, setState] = useState({ phase: "initiating" }); + const [authCode, setAuthCode] = useState(""); const pollingRef = useRef | null>(null); // Cleanup polling on unmount @@ -135,21 +137,71 @@ function ReauthModal({ }; }, [daemon.id, startPolling]); - // When URL is shown, transition to waiting_for_auth after user clicks the link - const handleOpenedLink = useCallback(() => { - setState((prev) => { - if (prev.phase === "url_ready") { - return { - phase: "waiting_for_auth", - loginUrl: prev.loginUrl, - requestId: prev.requestId, - }; + const handleSubmitCode = useCallback( + async (e: React.FormEvent) => { + e.preventDefault(); + if (!authCode.trim() || state.phase !== "url_ready") return; + + const requestId = state.requestId; + setState({ phase: "submitting", requestId }); + + try { + await submitDaemonAuthCode(daemon.id, authCode.trim(), requestId); + + // Poll for completion + pollingRef.current = setInterval(async () => { + try { + const status = await getDaemonReauthStatus( + daemon.id, + requestId, + ); + if (status.status === "completed") { + setState({ phase: "success" }); + if (pollingRef.current) { + clearInterval(pollingRef.current); + pollingRef.current = null; + } + } else if (status.status === "failed") { + setState({ + phase: "error", + message: status.error || "Auth code submission failed", + }); + if (pollingRef.current) { + clearInterval(pollingRef.current); + pollingRef.current = null; + } + } + } catch { + // Keep polling + } + }, 2000); + + // Also set a timeout so we don't poll forever + setTimeout(() => { + if (pollingRef.current) { + clearInterval(pollingRef.current); + pollingRef.current = null; + } + // If still submitting after 30s, assume success (setup-token completed) + setState((prev) => + prev.phase === "submitting" ? { phase: "success" } : prev, + ); + }, 30000); + } catch (err) { + setState({ + phase: "error", + message: + err instanceof Error + ? err.message + : "Failed to submit auth code", + }); } - return prev; - }); - }, []); + }, + [authCode, daemon.id, state], + ); const handleRetry = useCallback(() => { + setAuthCode(""); setState({ phase: "initiating" }); const trigger = async () => { try { @@ -197,50 +249,46 @@ function ReauthModal({ )} - {/* URL Ready - user needs to click the link */} + {/* URL Ready */} {state.phase === "url_ready" && (

- Click the button below to open the OAuth login page. Authentication will complete automatically. + Click the button below to open the OAuth login page, then paste the code:

- Login to Claude + 1. Login to Claude -
-
- - Waiting for authentication to complete... - -
+
+ setAuthCode(e.target.value)} + placeholder="2. Paste authentication code" + className="flex-1 bg-[#0a1525] border border-amber-500/30 px-3 py-2 text-xs font-mono text-amber-100 placeholder-amber-500/50 focus:outline-none focus:border-amber-400" + /> + +
)} - {/* Waiting for auth - user has clicked the link, waiting for token */} - {state.phase === "waiting_for_auth" && ( -
-
-
- - Waiting for authentication to complete... - -
-

- Complete the login in your browser. The token will be saved automatically. -

- - Open login page again - + {/* Submitting */} + {state.phase === "submitting" && ( +
+
+ + Submitting auth code... +
)} -- cgit v1.2.3