diff --git a/src/agents/auth-profiles.store.save.test.ts b/src/agents/auth-profiles.store.save.test.ts index 3bd309986af..cc647c9dd9a 100644 --- a/src/agents/auth-profiles.store.save.test.ts +++ b/src/agents/auth-profiles.store.save.test.ts @@ -131,6 +131,41 @@ describe("saveAuthProfileStore", () => { } }); + it("does not persist compatibility-only external oauth ownership metadata", async () => { + const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-save-managedby-")); + try { + const store: AuthProfileStore = { + version: 1, + profiles: { + "openai-codex:default": { + type: "oauth", + provider: "openai-codex", + access: "access-token", + refresh: "refresh-token", + expires: 123, + managedBy: "codex-cli", + }, + }, + }; + + saveAuthProfileStore(store, agentDir); + + const persisted = JSON.parse(await fs.readFile(resolveAuthStorePath(agentDir), "utf8")) as { + profiles: Record>; + }; + expect(persisted.profiles["openai-codex:default"]).toMatchObject({ + type: "oauth", + provider: "openai-codex", + access: "access-token", + refresh: "refresh-token", + expires: 123, + }); + expect(persisted.profiles["openai-codex:default"]?.managedBy).toBeUndefined(); + } finally { + await fs.rm(agentDir, { recursive: true, force: true }); + } + }); + it("writes runtime scheduling state to auth-state.json only", async () => { const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-save-state-")); try { diff --git a/src/agents/auth-profiles/persisted.ts b/src/agents/auth-profiles/persisted.ts index d6fc059bf99..7aa71a6684e 100644 --- a/src/agents/auth-profiles/persisted.ts +++ b/src/agents/auth-profiles/persisted.ts @@ -192,6 +192,10 @@ export function buildPersistedAuthProfileSecretsStore( if (shouldPersistProfile && !shouldPersistProfile({ profileId, credential })) { return []; } + if (credential.type === "oauth" && credential.managedBy) { + const { managedBy: _managedBy, ...canonicalCredential } = credential; + return [[profileId, canonicalCredential]]; + } if (credential.type === "api_key" && credential.keyRef && credential.key !== undefined) { const sanitized = { ...credential } as Record; delete sanitized.key; @@ -245,7 +249,6 @@ export function applyLegacyAuthStore(store: AuthProfileStore, legacy: LegacyAuth ...(cred.projectId ? { projectId: cred.projectId } : {}), ...(cred.accountId ? { accountId: cred.accountId } : {}), ...(cred.email ? { email: cred.email } : {}), - ...(cred.managedBy ? { managedBy: cred.managedBy } : {}), }; } } diff --git a/src/agents/cli-auth-epoch.test.ts b/src/agents/cli-auth-epoch.test.ts index 6f9d860888c..97e3d7e325c 100644 --- a/src/agents/cli-auth-epoch.test.ts +++ b/src/agents/cli-auth-epoch.test.ts @@ -141,4 +141,50 @@ describe("resolveCliAuthEpoch", () => { expect(second).not.toBe(first); expect(third).not.toBe(second); }); + + it("ignores compatibility-only managedBy metadata on auth profiles", async () => { + let store: AuthProfileStore = { + version: 1, + profiles: { + "openai-codex:default": { + type: "oauth", + provider: "openai-codex", + access: "profile-access", + refresh: "profile-refresh", + expires: 1, + managedBy: "codex-cli", + }, + }, + }; + setCliAuthEpochTestDeps({ + loadAuthProfileStoreForRuntime: () => store, + }); + + const first = await resolveCliAuthEpoch({ + provider: "codex-cli", + authProfileId: "openai-codex:default", + }); + + store = { + version: 1, + profiles: { + "openai-codex:default": { + type: "oauth", + provider: "openai-codex", + access: "profile-access", + refresh: "profile-refresh", + expires: 1, + }, + }, + }; + + const second = await resolveCliAuthEpoch({ + provider: "codex-cli", + authProfileId: "openai-codex:default", + }); + + expect(first).toBeDefined(); + expect(second).toBeDefined(); + expect(second).toBe(first); + }); }); diff --git a/src/agents/cli-auth-epoch.ts b/src/agents/cli-auth-epoch.ts index 3b7721c207b..ae1c6d28173 100644 --- a/src/agents/cli-auth-epoch.ts +++ b/src/agents/cli-auth-epoch.ts @@ -98,7 +98,6 @@ function encodeAuthProfileCredential(credential: AuthProfileCredential): string credential.enterpriseUrl ?? null, credential.projectId ?? null, credential.accountId ?? null, - credential.managedBy ?? null, ]); } throw new Error("Unsupported auth profile credential type");