mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 00:21:23 +00:00
fix(auth/session): preserve override reset behavior and repair oauth profile-id drift (openclaw#18820) thanks @Glucksberg
Verified: - pnpm build - pnpm check - pnpm test:macmini Co-authored-by: Glucksberg <80581902+Glucksberg@users.noreply.github.com> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
@@ -68,11 +68,7 @@ export async function applyAuthChoiceOAuth(
|
||||
});
|
||||
|
||||
spin.stop("Chutes OAuth complete");
|
||||
const email =
|
||||
typeof creds.email === "string" && creds.email.trim() ? creds.email.trim() : "default";
|
||||
const profileId = `chutes:${email}`;
|
||||
|
||||
await writeOAuthCredentials("chutes", creds, params.agentDir);
|
||||
const profileId = await writeOAuthCredentials("chutes", creds, params.agentDir);
|
||||
nextConfig = applyAuthProfileConfig(nextConfig, {
|
||||
profileId,
|
||||
provider: "chutes",
|
||||
|
||||
@@ -117,9 +117,9 @@ export async function applyAuthChoiceOpenAI(
|
||||
return { config: nextConfig, agentModelOverride };
|
||||
}
|
||||
if (creds) {
|
||||
await writeOAuthCredentials("openai-codex", creds, params.agentDir);
|
||||
const profileId = await writeOAuthCredentials("openai-codex", creds, params.agentDir);
|
||||
nextConfig = applyAuthProfileConfig(nextConfig, {
|
||||
profileId: "openai-codex:default",
|
||||
profileId,
|
||||
provider: "openai-codex",
|
||||
mode: "oauth",
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import fs from "node:fs/promises";
|
||||
import type { OAuthCredentials } from "@mariozechner/pi-ai";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import type { WizardPrompter } from "../wizard/prompts.js";
|
||||
import { applyAuthChoice, resolvePreferredProviderForAuthChoice } from "./auth-choice.js";
|
||||
@@ -22,7 +23,9 @@ vi.mock("../providers/github-copilot-auth.js", () => ({
|
||||
githubCopilotLoginCommand: vi.fn(async () => {}),
|
||||
}));
|
||||
|
||||
const loginOpenAICodexOAuth = vi.hoisted(() => vi.fn(async () => null));
|
||||
const loginOpenAICodexOAuth = vi.hoisted(() =>
|
||||
vi.fn<() => Promise<OAuthCredentials | null>>(async () => null),
|
||||
);
|
||||
vi.mock("./openai-codex-oauth.js", () => ({
|
||||
loginOpenAICodexOAuth,
|
||||
}));
|
||||
@@ -123,6 +126,41 @@ describe("applyAuthChoice", () => {
|
||||
).resolves.toEqual({ config: {} });
|
||||
});
|
||||
|
||||
it("stores openai-codex OAuth with email profile id", async () => {
|
||||
await setupTempState();
|
||||
|
||||
loginOpenAICodexOAuth.mockResolvedValueOnce({
|
||||
email: "user@example.com",
|
||||
refresh: "refresh-token",
|
||||
access: "access-token",
|
||||
expires: Date.now() + 60_000,
|
||||
});
|
||||
|
||||
const prompter = createPrompter({});
|
||||
const runtime = createExitThrowingRuntime();
|
||||
|
||||
const result = await applyAuthChoice({
|
||||
authChoice: "openai-codex",
|
||||
config: {},
|
||||
prompter,
|
||||
runtime,
|
||||
setDefaultModel: false,
|
||||
});
|
||||
|
||||
expect(result.config.auth?.profiles?.["openai-codex:user@example.com"]).toMatchObject({
|
||||
provider: "openai-codex",
|
||||
mode: "oauth",
|
||||
});
|
||||
expect(result.config.auth?.profiles?.["openai-codex:default"]).toBeUndefined();
|
||||
expect(await readAuthProfile("openai-codex:user@example.com")).toMatchObject({
|
||||
type: "oauth",
|
||||
provider: "openai-codex",
|
||||
refresh: "refresh-token",
|
||||
access: "access-token",
|
||||
email: "user@example.com",
|
||||
});
|
||||
});
|
||||
|
||||
it("prompts and writes MiniMax API key when selecting minimax-api", async () => {
|
||||
await setupTempState();
|
||||
|
||||
|
||||
@@ -10,11 +10,12 @@ export async function writeOAuthCredentials(
|
||||
provider: string,
|
||||
creds: OAuthCredentials,
|
||||
agentDir?: string,
|
||||
): Promise<void> {
|
||||
): Promise<string> {
|
||||
const email =
|
||||
typeof creds.email === "string" && creds.email.trim() ? creds.email.trim() : "default";
|
||||
const profileId = `${provider}:${email}`;
|
||||
upsertAuthProfile({
|
||||
profileId: `${provider}:${email}`,
|
||||
profileId,
|
||||
credential: {
|
||||
type: "oauth",
|
||||
provider,
|
||||
@@ -22,6 +23,7 @@ export async function writeOAuthCredentials(
|
||||
},
|
||||
agentDir: resolveAuthAgentDir(agentDir),
|
||||
});
|
||||
return profileId;
|
||||
}
|
||||
|
||||
export async function setAnthropicApiKey(key: string, agentDir?: string) {
|
||||
|
||||
@@ -125,12 +125,13 @@ describe("writeOAuthCredentials", () => {
|
||||
expires: Date.now() + 60_000,
|
||||
} satisfies OAuthCredentials;
|
||||
|
||||
await writeOAuthCredentials("openai-codex", creds);
|
||||
const profileId = await writeOAuthCredentials("openai-codex", creds);
|
||||
expect(profileId).toBe("openai-codex:default");
|
||||
|
||||
const parsed = await readAuthProfilesForAgent<{
|
||||
profiles?: Record<string, OAuthCredentials & { type?: string }>;
|
||||
}>(env.agentDir);
|
||||
expect(parsed.profiles?.["openai-codex:default"]).toMatchObject({
|
||||
expect(parsed.profiles?.[profileId]).toMatchObject({
|
||||
refresh: "refresh-token",
|
||||
access: "access-token",
|
||||
type: "oauth",
|
||||
@@ -140,6 +141,32 @@ describe("writeOAuthCredentials", () => {
|
||||
fs.readFile(path.join(env.stateDir, "agents", "main", "agent", "auth-profiles.json"), "utf8"),
|
||||
).rejects.toThrow();
|
||||
});
|
||||
|
||||
it("uses OAuth email as profile id when provided", async () => {
|
||||
const env = await setupAuthTestEnv("openclaw-oauth-");
|
||||
lifecycle.setStateDir(env.stateDir);
|
||||
|
||||
const creds = {
|
||||
email: "user@example.com",
|
||||
refresh: "refresh-token",
|
||||
access: "access-token",
|
||||
expires: Date.now() + 60_000,
|
||||
} satisfies OAuthCredentials;
|
||||
|
||||
const profileId = await writeOAuthCredentials("openai-codex", creds);
|
||||
expect(profileId).toBe("openai-codex:user@example.com");
|
||||
|
||||
const parsed = await readAuthProfilesForAgent<{
|
||||
profiles?: Record<string, OAuthCredentials & { type?: string }>;
|
||||
}>(env.agentDir);
|
||||
expect(parsed.profiles?.[profileId]).toMatchObject({
|
||||
refresh: "refresh-token",
|
||||
access: "access-token",
|
||||
type: "oauth",
|
||||
provider: "openai-codex",
|
||||
email: "user@example.com",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("setMinimaxApiKey", () => {
|
||||
|
||||
Reference in New Issue
Block a user