Skip to content

Commit 51d9833

Browse files
lishengzxcclaude
andcommitted
fix(auth): parse baseUrl/consoleSite/consoleRegion/consoleSwitchAgent from POST body
These fields were only extracted from query params but the console sends them in the JSON POST body. Add parseExtrasFromRawBody() to handle JSON and form-urlencoded bodies. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent e68abb6 commit 51d9833

2 files changed

Lines changed: 83 additions & 4 deletions

File tree

packages/cli/src/commands/auth/login-console.ts

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,66 @@ function parseApiKeyFromRawBody(raw: string, contentType: string): string | null
210210
return null;
211211
}
212212

213+
type CallbackExtras = Pick<
214+
CallbackCredentials,
215+
"baseUrl" | "consoleSite" | "consoleRegion" | "consoleSwitchAgent"
216+
>;
217+
218+
function stringField(o: Record<string, unknown>, ...keys: string[]): string | null {
219+
for (const k of keys) {
220+
const v = o[k];
221+
if (typeof v === "string" && v.trim()) return v.trim();
222+
}
223+
return null;
224+
}
225+
226+
function parseExtrasFromRawBody(raw: string, contentType: string): CallbackExtras {
227+
const empty: CallbackExtras = {
228+
baseUrl: null,
229+
consoleSite: null,
230+
consoleRegion: null,
231+
consoleSwitchAgent: null,
232+
};
233+
if (!raw.trim()) return empty;
234+
235+
let obj: Record<string, unknown> | null = null;
236+
237+
const ct = contentType.toLowerCase();
238+
if (ct.includes("application/json") || ct.includes("text/json")) {
239+
try {
240+
const parsed = JSON.parse(raw.trim());
241+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) obj = parsed;
242+
} catch {
243+
/* */
244+
}
245+
}
246+
if (!obj && ct.includes("application/x-www-form-urlencoded")) {
247+
try {
248+
const params = new URLSearchParams(raw.trim());
249+
obj = Object.fromEntries(params);
250+
} catch {
251+
/* */
252+
}
253+
}
254+
if (!obj) {
255+
try {
256+
const parsed = JSON.parse(raw.trim());
257+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) obj = parsed;
258+
} catch {
259+
/* */
260+
}
261+
}
262+
263+
if (!obj) return empty;
264+
265+
return {
266+
baseUrl: stringField(obj, "base_url", "baseUrl"),
267+
consoleSite: stringField(obj, "console_site", "consoleSite"),
268+
consoleRegion: stringField(obj, "console_region", "consoleRegion"),
269+
consoleSwitchAgent: stringField(obj, "console_switch_agent", "consoleSwitchAgent"),
270+
};
271+
}
272+
213273
interface CallbackCredentials {
214274
accessToken: string | null;
215275
apiKey: string | null;
@@ -264,7 +324,17 @@ async function extractCredentialsFromRequest(
264324

265325
const accessToken = accessTokenFromQuery?.trim() || parseAccessTokenFromRawBody(raw, contentType);
266326
const apiKey = apiKeyFromQuery?.trim() || parseApiKeyFromRawBody(raw, contentType);
267-
return { accessToken, apiKey, ...extras };
327+
328+
const bodyExtras = parseExtrasFromRawBody(raw, contentType);
329+
330+
return {
331+
accessToken,
332+
apiKey,
333+
baseUrl: extras.baseUrl || bodyExtras.baseUrl,
334+
consoleSite: extras.consoleSite || bodyExtras.consoleSite,
335+
consoleRegion: extras.consoleRegion || bodyExtras.consoleRegion,
336+
consoleSwitchAgent: extras.consoleSwitchAgent || bodyExtras.consoleSwitchAgent,
337+
};
268338
}
269339

270340
function listenServerOnFreeLocalPort(server: http.Server): Promise<number> {
@@ -298,7 +368,10 @@ function openInBrowser(url: string): Promise<void> {
298368

299369
export async function runConsoleLogin(
300370
consoleOrigin: string,
301-
opts?: { needApiKey?: boolean; onApiKey?: (key: string) => Promise<void> },
371+
opts?: {
372+
needApiKey?: boolean;
373+
onApiKey?: ({ apiKey, baseUrl }: { apiKey: string; baseUrl?: string }) => Promise<void>;
374+
},
302375
): Promise<void> {
303376
const state = randomBytes(16).toString("hex");
304377
let callbackError: unknown;
@@ -323,6 +396,8 @@ export async function runConsoleLogin(
323396

324397
const { accessToken, apiKey, baseUrl, consoleSite, consoleRegion, consoleSwitchAgent } =
325398
await extractCredentialsFromRequest(req);
399+
400+
console.log({ accessToken, apiKey, baseUrl, consoleSite, consoleRegion, consoleSwitchAgent });
326401
const hasConfig =
327402
accessToken || baseUrl || consoleSite || consoleRegion || consoleSwitchAgent;
328403

@@ -339,7 +414,7 @@ export async function runConsoleLogin(
339414
process.stderr.write(`Config saved to ${getConfigPath()}\n`);
340415
}
341416
if (apiKey && opts?.onApiKey) {
342-
await opts.onApiKey(apiKey);
417+
await opts.onApiKey({ apiKey, baseUrl: baseUrl ?? undefined });
343418
}
344419
} catch (err: unknown) {
345420
callbackError = err;

packages/cli/src/commands/auth/login.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ function canRetry(err: unknown): boolean {
4141

4242
async function validateKeyAndPersist(config: Config, key: string): Promise<void> {
4343
process.stderr.write("Testing key... ");
44+
process.stderr.write("\r\n" + JSON.stringify(config));
45+
4446
const testConfig = { ...config, apiKey: key };
4547
const requestOpts = {
4648
url: chatEndpoint(testConfig.baseUrl),
@@ -102,7 +104,9 @@ export default defineCommand({
102104
const hasApiKey = !!(config.apiKey || config.fileApiKey);
103105
await runConsoleLogin(resolveConsoleOrigin(), {
104106
needApiKey: !hasApiKey,
105-
onApiKey: (key) => validateKeyAndPersist(config, key),
107+
onApiKey: ({ apiKey, baseUrl }) => {
108+
return validateKeyAndPersist({ ...config, ...(baseUrl ? { baseUrl } : {}) }, apiKey);
109+
},
106110
});
107111
return;
108112
}

0 commit comments

Comments
 (0)