fix(oauth): expose manual Codex callback entry

This commit is contained in:
OpenClaw Auto
2026-08-09 22:02:27 +03:00
parent c130f2aa1c
commit 18e4ccf58f
4 changed files with 35 additions and 6 deletions

View File

@@ -0,0 +1 @@
Add a visible manual callback-entry action to the Codex loopback warning so remote users can paste the authorization result instead of setting up an SSH tunnel.

View File

@@ -372,11 +372,10 @@ export default function OAuthModal({
[provider, onSuccess, reauthConnection, t]
);
// Start OAuth flow. `opts.grokBrowser` lets the grok-cli method tabs force a
// specific branch synchronously (avoids reading a just-set state value through
// a stale closure); when omitted, falls back to the grokBrowserMode state.
// Start OAuth flow. Options let method buttons select a branch synchronously
// instead of reading a just-set state value through a stale closure.
const startOAuthFlow = useCallback(
async (opts?: { grokBrowser?: boolean }) => {
async (opts?: { grokBrowser?: boolean; manualLoopback?: boolean }) => {
if (!provider) return;
try {
setError(null);
@@ -531,7 +530,7 @@ export default function OAuthModal({
setPolling(false);
forceManual = true;
}
} else if (isLocalhost) {
} else if (isLocalhost && !opts?.manualLoopback) {
setLoopbackHint(buildPkceLoopbackMismatchHint(provider, loopbackLocation));
setStep("loopback-mismatch");
return;
@@ -1124,6 +1123,7 @@ export default function OAuthModal({
<OAuthLoopbackMismatchPanel
providerName={providerInfo.name}
hint={loopbackHint}
onManualInput={() => void startOAuthFlow({ manualLoopback: true })}
onClose={handleClose}
/>
)}

View File

@@ -89,6 +89,7 @@ export function OAuthDeviceCodePanel({
type OAuthLoopbackMismatchPanelProps = {
providerName: string;
hint: PkceLoopbackMismatchHint;
onManualInput: () => void;
onClose: () => void;
};
@@ -103,6 +104,7 @@ type OAuthLoopbackMismatchPanelProps = {
export function OAuthLoopbackMismatchPanel({
providerName,
hint,
onManualInput,
onClose,
}: OAuthLoopbackMismatchPanelProps) {
const t = useTranslations("oauthModal");
@@ -194,6 +196,9 @@ export function OAuthLoopbackMismatchPanel({
<p className="text-xs text-text-muted">{t("loopbackMismatchAlternative")}</p>
</div>
<div className="flex gap-2">
<Button onClick={onManualInput} fullWidth>
{t("popupBlocked")}
</Button>
<Button onClick={onClose} variant="secondary" fullWidth>
{t("cancel")}
</Button>

View File

@@ -41,7 +41,7 @@ test("PKCE callback-server providers now warn (not window.open) on a LAN-IP orig
// that surfaces the loopback mismatch instead of falling through silently.
// The follow-up swapped the flat warning string for the structured hint that feeds
// the dedicated panel (buildPkceLoopbackMismatchHint) — the guard itself is unchanged.
const arm = modal.match(/else if \(isLocalhost\) \{[\s\S]{0,300}?\n {10}\}/);
const arm = modal.match(/else if \(isLocalhost(?: && [^)]+)?\) \{[\s\S]{0,300}?\n {10}\}/);
assert.ok(arm, "expected an `else if (isLocalhost)` arm inside the callback-server branch");
assert.match(
arm![0],
@@ -57,6 +57,29 @@ test("PKCE callback-server providers now warn (not window.open) on a LAN-IP orig
);
});
test("loopback warning offers the existing manual callback flow", () => {
const panels = readFileSync(
resolve(here, "../../src/shared/components/OAuthModalPanels.tsx"),
"utf8"
);
assert.match(
modal,
/isLocalhost && !opts\?\.manualLoopback/,
"the warning guard must be bypassable only through an explicit manual-flow action"
);
assert.match(
modal,
/onManualInput=\{\(\) => void startOAuthFlow\(\{ manualLoopback: true \}\)\}/,
"the mismatch panel action must initialize the existing authorization-code flow"
);
assert.match(
panels,
/<Button onClick=\{onManualInput\} fullWidth>/,
"the mismatch panel must render a visible manual-entry action next to Cancel"
);
});
test("buildPkceLoopbackMismatchWarning mentions the fixed redirect and a way forward", () => {
const msg = buildPkceLoopbackMismatchWarning("codex");
assert.match(msg, /localhost:1455/);