mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-18 19:04:45 +00:00
fix(auth): accept oauthRef profiles for runtime auth
This commit is contained in:
@@ -12,6 +12,7 @@ import {
|
||||
bridgeCodexAppServerStartOptions,
|
||||
refreshCodexAppServerAuthTokens,
|
||||
resolveCodexAppServerAuthAccountCacheKey,
|
||||
resolveCodexAppServerAuthProfileId,
|
||||
resolveCodexAppServerHomeDir,
|
||||
resolveCodexAppServerNativeHomeDir,
|
||||
} from "./auth-bridge.js";
|
||||
@@ -651,6 +652,30 @@ describe("bridgeCodexAppServerStartOptions", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it("selects an oauthRef-backed Codex profile for app-server login", () => {
|
||||
expect(
|
||||
resolveCodexAppServerAuthProfileId({
|
||||
store: {
|
||||
version: 1,
|
||||
profiles: {
|
||||
"openai-codex:default": {
|
||||
type: "oauth",
|
||||
provider: "openai-codex",
|
||||
access: "",
|
||||
refresh: "",
|
||||
expires: Date.now() + 60_000,
|
||||
oauthRef: {
|
||||
source: "openclaw-credentials",
|
||||
provider: "openai-codex",
|
||||
id: "0123456789abcdef0123456789abcdef",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
).toBe("openai-codex:default");
|
||||
});
|
||||
|
||||
it("applies native Codex CLI OAuth when no OpenClaw auth profile exists", async () => {
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-codex-app-server-"));
|
||||
const agentDir = path.join(root, "agent");
|
||||
|
||||
@@ -103,4 +103,23 @@ describe("evaluateStoredCredentialEligibility", () => {
|
||||
});
|
||||
expect(result).toEqual({ eligible: false, reasonCode: "invalid_expires" });
|
||||
});
|
||||
|
||||
it("marks oauth with oauthRef as eligible", () => {
|
||||
const result = evaluateStoredCredentialEligibility({
|
||||
credential: {
|
||||
type: "oauth",
|
||||
provider: "openai-codex",
|
||||
access: "",
|
||||
refresh: "",
|
||||
expires: now + 60_000,
|
||||
oauthRef: {
|
||||
source: "openclaw-credentials",
|
||||
provider: "openai-codex",
|
||||
id: "0123456789abcdef0123456789abcdef",
|
||||
},
|
||||
},
|
||||
now,
|
||||
});
|
||||
expect(result).toEqual({ eligible: true, reasonCode: "ok" });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { coerceSecretRef, normalizeSecretInputString } from "../../config/types.secrets.js";
|
||||
import type { AuthProfileCredential, OAuthCredential } from "./types.js";
|
||||
import type { AuthProfileCredential, OAuthCredential, OAuthCredentialRef } from "./types.js";
|
||||
|
||||
export type AuthCredentialReasonCode =
|
||||
| "ok"
|
||||
@@ -69,6 +69,15 @@ function hasConfiguredSecretString(value: unknown): boolean {
|
||||
return normalizeSecretInputString(value) !== undefined;
|
||||
}
|
||||
|
||||
function hasConfiguredOAuthRef(value: OAuthCredentialRef | undefined): boolean {
|
||||
return (
|
||||
value?.source === "openclaw-credentials" &&
|
||||
value.provider === "openai-codex" &&
|
||||
typeof value.id === "string" &&
|
||||
/^[a-f0-9]{32}$/.test(value.id)
|
||||
);
|
||||
}
|
||||
|
||||
export function evaluateStoredCredentialEligibility(params: {
|
||||
credential: AuthProfileCredential;
|
||||
now?: number;
|
||||
@@ -104,7 +113,8 @@ export function evaluateStoredCredentialEligibility(params: {
|
||||
|
||||
if (
|
||||
normalizeSecretInputString(credential.access) === undefined &&
|
||||
normalizeSecretInputString(credential.refresh) === undefined
|
||||
normalizeSecretInputString(credential.refresh) === undefined &&
|
||||
!hasConfiguredOAuthRef(credential.oauthRef)
|
||||
) {
|
||||
return { eligible: false, reasonCode: "missing_credential" };
|
||||
}
|
||||
|
||||
@@ -276,6 +276,33 @@ describe("resolveAuthProfileOrder", () => {
|
||||
expect(order).toEqual(["openai-codex:personal", "openai:backup"]);
|
||||
});
|
||||
|
||||
it("lets Codex auth discover oauthRef-backed OAuth profiles", async () => {
|
||||
const store: AuthProfileStore = {
|
||||
version: 1,
|
||||
profiles: {
|
||||
"openai-codex:personal": {
|
||||
type: "oauth",
|
||||
provider: "openai-codex",
|
||||
access: "",
|
||||
refresh: "",
|
||||
expires: Date.now() + 60_000,
|
||||
oauthRef: {
|
||||
source: "openclaw-credentials",
|
||||
provider: "openai-codex",
|
||||
id: "0123456789abcdef0123456789abcdef",
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const order = resolveAuthProfileOrder({
|
||||
store,
|
||||
provider: "openai-codex",
|
||||
});
|
||||
|
||||
expect(order).toEqual(["openai-codex:personal"]);
|
||||
});
|
||||
|
||||
it("preserves native Codex profiles before OpenAI alias API-key order", async () => {
|
||||
const store: AuthProfileStore = {
|
||||
version: 1,
|
||||
|
||||
Reference in New Issue
Block a user