fix(FN-1952): read legacy oauth auth

This commit is contained in:
gsxdsm
2026-04-16 21:16:48 -07:00
parent a313037cca
commit 22e411a82b
5 changed files with 149 additions and 11 deletions

View File

@@ -42,6 +42,46 @@ describe("createFusionAuthStorage", () => {
expect(existsSync(getFusionAuthPath(homeDir))).toBe(true);
});
it("reads non-expired legacy Pi OAuth credentials as fallback", async () => {
const legacyAgentDir = join(homeDir, ".pi", "agent");
mkdirSync(legacyAgentDir, { recursive: true });
writeFileSync(
join(legacyAgentDir, "auth.json"),
JSON.stringify({
"openai-codex": {
type: "oauth",
access: "legacy-access-token",
refresh: "legacy-refresh-token",
expires: Date.now() + 60_000,
},
}),
);
const authStorage = createFusionAuthStorage();
expect(await authStorage.getApiKey("openai-codex")).toBe("legacy-access-token");
});
it("does not use expired legacy Pi OAuth credentials", async () => {
const legacyAgentDir = join(homeDir, ".pi", "agent");
mkdirSync(legacyAgentDir, { recursive: true });
writeFileSync(
join(legacyAgentDir, "auth.json"),
JSON.stringify({
"openai-codex": {
type: "oauth",
access: "expired-access-token",
refresh: "legacy-refresh-token",
expires: Date.now() - 60_000,
},
}),
);
const authStorage = createFusionAuthStorage();
expect(await authStorage.getApiKey("openai-codex")).toBeUndefined();
});
it("does not create missing legacy Pi auth files", async () => {
const authStorage = createFusionAuthStorage();

View File

@@ -2,8 +2,17 @@ import { existsSync, readFileSync } from "node:fs";
import { homedir } from "node:os";
import { join } from "node:path";
import { AuthStorage } from "@mariozechner/pi-coding-agent";
import { getOAuthProvider } from "@mariozechner/pi-ai/oauth";
import type { OAuthCredentials } from "@mariozechner/pi-ai/oauth";
type StoredCredential = { type?: string; key?: string };
type StoredCredential = {
type?: string;
key?: string;
access?: string;
refresh?: string;
expires?: number;
[key: string]: unknown;
};
function getHomeDir(): string {
return process.env.HOME || process.env.USERPROFILE || homedir();
@@ -45,6 +54,30 @@ function resolveStoredApiKey(key: string | undefined): string | undefined {
return process.env[key] ?? key;
}
function resolveOAuthApiKey(providerId: string, credential: StoredCredential): string | undefined {
if (
credential.type !== "oauth" ||
typeof credential.access !== "string" ||
typeof credential.refresh !== "string" ||
typeof credential.expires !== "number" ||
Date.now() >= credential.expires
) {
return undefined;
}
return getOAuthProvider(providerId)?.getApiKey(credential as OAuthCredentials);
}
function resolveStoredCredentialApiKey(providerId: string, credential: StoredCredential | undefined): string | undefined {
if (credential?.type === "api_key") {
return resolveStoredApiKey(credential.key);
}
if (credential?.type === "oauth") {
return resolveOAuthApiKey(providerId, credential);
}
return undefined;
}
export function createFusionAuthStorage(): AuthStorage {
const primary = AuthStorage.create(getFusionAuthPath());
let legacyCredentials = readLegacyCredentials();
@@ -83,8 +116,7 @@ export function createFusionAuthStorage(): AuthStorage {
const primaryKey = await target.getApiKey(provider);
if (primaryKey) return primaryKey;
const credential = legacyCredentials[provider];
return credential?.type === "api_key" ? resolveStoredApiKey(credential.key) : undefined;
return resolveStoredCredentialApiKey(provider, legacyCredentials[provider]);
};
}