Skip to content

Commit a1eb834

Browse files
committed
fix(auth): unify authorize merge with storage identity semantics
1 parent 8192edf commit a1eb834

File tree

1 file changed

+13
-30
lines changed

1 file changed

+13
-30
lines changed

index.ts

Lines changed: 13 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,7 @@ export const OpenAIOAuthPlugin: Plugin = async ({ client }: PluginInput) => {
602602
byEmailNoOrg: Map<string, number>;
603603
byAccountIdOrgScoped: Map<string, number[]>;
604604
byRefreshTokenOrgScoped: Map<string, number[]>;
605-
byRefreshTokenGlobal: Map<string, number>;
605+
byRefreshTokenGlobal: Map<string, number[]>;
606606
};
607607

608608
const resolveUniqueOrgScopedMatch = (
@@ -629,7 +629,7 @@ export const OpenAIOAuthPlugin: Plugin = async ({ client }: PluginInput) => {
629629
const byEmailNoOrg = new Map<string, number>();
630630
const byAccountIdOrgScoped = new Map<string, number[]>();
631631
const byRefreshTokenOrgScoped = new Map<string, number[]>();
632-
const byRefreshTokenGlobal = new Map<string, number>();
632+
const byRefreshTokenGlobal = new Map<string, number[]>();
633633

634634
for (let i = 0; i < accounts.length; i += 1) {
635635
const account = accounts[i];
@@ -640,9 +640,10 @@ export const OpenAIOAuthPlugin: Plugin = async ({ client }: PluginInput) => {
640640
const refreshToken = account.refreshToken?.trim();
641641
const email = account.email?.trim();
642642

643-
// Global refresh token index: first entry wins (keeps earliest/primary).
644-
if (refreshToken && !byRefreshTokenGlobal.has(refreshToken)) {
645-
byRefreshTokenGlobal.set(refreshToken, i);
643+
// Track all refresh-token matches. Callers can require uniqueness
644+
// so org variants that share a token do not collapse accidentally.
645+
if (refreshToken) {
646+
pushIndex(byRefreshTokenGlobal, refreshToken, i);
646647
}
647648

648649
if (organizationId) {
@@ -722,9 +723,9 @@ export const OpenAIOAuthPlugin: Plugin = async ({ client }: PluginInput) => {
722723
);
723724
if (orgScoped !== undefined) return orgScoped;
724725

725-
// Absolute last resort: same refresh token = same human account.
726-
// Catches org-scoped entries invisible to no-org lookups.
727-
return identityIndexes.byRefreshTokenGlobal.get(result.refresh);
726+
// Absolute last resort: only collapse when refresh token maps to a
727+
// single account. Avoids merging distinct org-scoped variants.
728+
return asUniqueIndex(identityIndexes.byRefreshTokenGlobal.get(result.refresh));
728729
})();
729730

730731
if (existingIndex === undefined) {
@@ -821,28 +822,10 @@ export const OpenAIOAuthPlugin: Plugin = async ({ client }: PluginInput) => {
821822
entry.fallbackIndex = i;
822823
}
823824

824-
for (const entry of refreshMap.values()) {
825-
const fallbackIndex = entry.fallbackIndex;
826-
if (typeof fallbackIndex !== "number") continue;
827-
const orgIndices = Array.from(entry.byOrg.values());
828-
if (orgIndices.length === 0) continue;
829-
830-
const [firstOrgIndex, ...otherOrgIndices] = orgIndices;
831-
if (typeof firstOrgIndex !== "number") continue;
832-
833-
let preferredOrgIndex = firstOrgIndex;
834-
for (const orgIndex of otherOrgIndices) {
835-
preferredOrgIndex = pickNewestAccountIndex(preferredOrgIndex, orgIndex);
836-
}
837-
838-
mergeAccountRecords(preferredOrgIndex, fallbackIndex);
839-
indicesToRemove.add(fallbackIndex);
840-
}
841-
842-
if (indicesToRemove.size > 0) {
843-
accounts = accounts.filter((_, index) => !indicesToRemove.has(index));
844-
}
845-
};
825+
if (indicesToRemove.size > 0) {
826+
accounts = accounts.filter((_, index) => !indicesToRemove.has(index));
827+
}
828+
};
846829

847830
const collectIdentityKeys = (
848831
account: { organizationId?: string; accountId?: string; refreshToken?: string } | undefined,

0 commit comments

Comments
 (0)