Skip to content

Commit 305a443

Browse files
committed
refactor(auth): centralize OAuth identity matching
1 parent 65adb13 commit 305a443

2 files changed

Lines changed: 10 additions & 51 deletions

File tree

src/agents/auth-profiles/external-cli-sync.ts

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
OPENAI_CODEX_DEFAULT_PROFILE_ID,
1717
} from "./constants.js";
1818
import { log } from "./constants.js";
19+
import { isSafeToCopyOAuthIdentity } from "./oauth-identity.js";
1920
import {
2021
areOAuthCredentialsEquivalent,
2122
hasUsableOAuthCredential,
@@ -61,15 +62,6 @@ type ExternalCliSyncProvider = {
6162
bootstrapOnly?: boolean;
6263
};
6364

64-
function normalizeAuthIdentityToken(value: string | undefined): string | undefined {
65-
const trimmed = value?.trim();
66-
return trimmed ? trimmed : undefined;
67-
}
68-
69-
function normalizeAuthEmailToken(value: string | undefined): string | undefined {
70-
return normalizeAuthIdentityToken(value)?.toLowerCase();
71-
}
72-
7365
// Keep this gate aligned with the canonical identity-copy rule in oauth.ts.
7466
/** Return true when imported CLI credentials match an existing profile identity. */
7567
export function isSafeToUseExternalCliCredential(
@@ -82,24 +74,7 @@ export function isSafeToUseExternalCliCredential(
8274
if (existing.provider !== imported.provider) {
8375
return false;
8476
}
85-
86-
const existingAccountId = normalizeAuthIdentityToken(existing.accountId);
87-
const importedAccountId = normalizeAuthIdentityToken(imported.accountId);
88-
const existingEmail = normalizeAuthEmailToken(existing.email);
89-
const importedEmail = normalizeAuthEmailToken(imported.email);
90-
91-
if (existingAccountId !== undefined && importedAccountId !== undefined) {
92-
return existingAccountId === importedAccountId;
93-
}
94-
if (existingEmail !== undefined && importedEmail !== undefined) {
95-
return existingEmail === importedEmail;
96-
}
97-
98-
const existingHasIdentity = existingAccountId !== undefined || existingEmail !== undefined;
99-
if (existingHasIdentity) {
100-
return false;
101-
}
102-
return true;
77+
return isSafeToCopyOAuthIdentity(existing, imported);
10378
}
10479

10580
const EXTERNAL_CLI_SYNC_PROVIDERS: ExternalCliSyncProvider[] = [

src/agents/auth-profiles/oauth-shared.ts

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,15 @@
66
import { asDateTimestampMs } from "../../shared/number-coercion.js";
77
import { cloneAuthProfileStore } from "./clone.js";
88
import { hasUsableOAuthCredential as hasUsableStoredOAuthCredential } from "./credential-state.js";
9+
import {
10+
isSafeToCopyOAuthIdentity,
11+
normalizeAuthEmailToken,
12+
normalizeAuthIdentityToken,
13+
} from "./oauth-identity.js";
914
import type { AuthProfileStore, OAuthCredential } from "./types.js";
1015

16+
export { normalizeAuthEmailToken, normalizeAuthIdentityToken } from "./oauth-identity.js";
17+
1118
/** OAuth profile imported from a runtime external CLI source. */
1219
export type RuntimeExternalOAuthProfile = {
1320
profileId: string;
@@ -74,17 +81,6 @@ export function hasUsableOAuthCredential(
7481
return hasUsableStoredOAuthCredential(credential, { now });
7582
}
7683

77-
/** Normalizes account identity tokens for equality checks. */
78-
export function normalizeAuthIdentityToken(value: string | undefined): string | undefined {
79-
const trimmed = value?.trim();
80-
return trimmed ? trimmed : undefined;
81-
}
82-
83-
/** Normalizes auth email identity tokens for equality checks. */
84-
export function normalizeAuthEmailToken(value: string | undefined): string | undefined {
85-
return normalizeAuthIdentityToken(value)?.toLowerCase();
86-
}
87-
8884
/** Returns true when an OAuth credential has account or email identity. */
8985
export function hasOAuthIdentity(
9086
credential: Pick<OAuthCredential, "accountId" | "email">,
@@ -100,19 +96,7 @@ export function hasMatchingOAuthIdentity(
10096
existing: Pick<OAuthCredential, "accountId" | "email">,
10197
incoming: Pick<OAuthCredential, "accountId" | "email">,
10298
): boolean {
103-
const existingAccountId = normalizeAuthIdentityToken(existing.accountId);
104-
const incomingAccountId = normalizeAuthIdentityToken(incoming.accountId);
105-
if (existingAccountId !== undefined && incomingAccountId !== undefined) {
106-
return existingAccountId === incomingAccountId;
107-
}
108-
109-
const existingEmail = normalizeAuthEmailToken(existing.email);
110-
const incomingEmail = normalizeAuthEmailToken(incoming.email);
111-
if (existingEmail !== undefined && incomingEmail !== undefined) {
112-
return existingEmail === incomingEmail;
113-
}
114-
115-
return false;
99+
return hasOAuthIdentity(existing) && isSafeToCopyOAuthIdentity(existing, incoming);
116100
}
117101

118102
// Different adoption paths have different safety thresholds. Bootstrap can

0 commit comments

Comments
 (0)