fix(auth): refresh all OAuth profiles per provider
Previously, resolveOAuthToken() would return after finding the first valid profile for a provider, leaving other profiles expired. This caused multi-account setups to only refresh one account per provider. Additionally, the status display would show stale expiry times because it read credentials before the usage fetch triggered refreshes. Changes: - Renamed resolveOAuthToken() to resolveOAuthTokens() and changed it to collect all valid profiles instead of returning early - Updated resolveProviderAuths() to spread all resolved tokens - Added store re-read in list.status-command.ts after usage fetch to display refreshed credential state Fixes #3803
This commit is contained in:
parent
4583f88626
commit
7dad13cd3a
@ -14,6 +14,7 @@ Status: beta.
|
|||||||
- Memory Search: allow extra paths for memory indexing. (#3600) Thanks @kira-ariaki.
|
- Memory Search: allow extra paths for memory indexing. (#3600) Thanks @kira-ariaki.
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
|
- Auth: fix OAuth refresh only refreshing one profile per provider, leaving other accounts expired. (#3803)
|
||||||
- Providers: add Venice AI integration; update Moonshot Kimi references to kimi-k2.5; update MiniMax API endpoint/format. (#2762, #3064)
|
- Providers: add Venice AI integration; update Moonshot Kimi references to kimi-k2.5; update MiniMax API endpoint/format. (#2762, #3064)
|
||||||
- Providers: add Xiaomi MiMo (mimo-v2-flash) support and onboarding flow. (#3454) Thanks @WqyJh.
|
- Providers: add Xiaomi MiMo (mimo-v2-flash) support and onboarding flow. (#3454) Thanks @WqyJh.
|
||||||
- Telegram: quote replies, edit-message action, silent sends, sticker support + vision caching, linkPreview toggle, plugin sendPayload support. (#2900, #2394, #2382, #2548, #1700, #1917)
|
- Telegram: quote replies, edit-message action, silent sends, sticker support + vision caching, linkPreview toggle, plugin sendPayload support. (#2900, #2394, #2382, #2548, #1700, #1917)
|
||||||
|
|||||||
@ -528,6 +528,18 @@ export async function modelsStatusCommand(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Re-read auth health after usage fetch, which may have refreshed expired tokens
|
||||||
|
const refreshedStore = ensureAuthProfileStore();
|
||||||
|
const refreshedHealth = buildAuthHealthSummary({
|
||||||
|
store: refreshedStore,
|
||||||
|
cfg,
|
||||||
|
warnAfterMs: DEFAULT_OAUTH_WARN_MS,
|
||||||
|
providers,
|
||||||
|
});
|
||||||
|
const refreshedOauthProfiles = refreshedHealth.profiles.filter(
|
||||||
|
(profile) => profile.type === "oauth" || profile.type === "token",
|
||||||
|
);
|
||||||
|
|
||||||
const formatStatus = (status: string) => {
|
const formatStatus = (status: string) => {
|
||||||
if (status === "ok") return colorize(rich, theme.success, "ok");
|
if (status === "ok") return colorize(rich, theme.success, "ok");
|
||||||
if (status === "static") return colorize(rich, theme.muted, "static");
|
if (status === "static") return colorize(rich, theme.muted, "static");
|
||||||
@ -536,8 +548,8 @@ export async function modelsStatusCommand(
|
|||||||
return colorize(rich, theme.error, "expired");
|
return colorize(rich, theme.error, "expired");
|
||||||
};
|
};
|
||||||
|
|
||||||
const profilesByProvider = new Map<string, typeof oauthProfiles>();
|
const profilesByProvider = new Map<string, typeof refreshedOauthProfiles>();
|
||||||
for (const profile of oauthProfiles) {
|
for (const profile of refreshedOauthProfiles) {
|
||||||
const current = profilesByProvider.get(profile.provider);
|
const current = profilesByProvider.get(profile.provider);
|
||||||
if (current) current.push(profile);
|
if (current) current.push(profile);
|
||||||
else profilesByProvider.set(profile.provider, [profile]);
|
else profilesByProvider.set(profile.provider, [profile]);
|
||||||
|
|||||||
@ -123,10 +123,10 @@ function resolveXiaomiApiKey(): string | undefined {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function resolveOAuthToken(params: {
|
async function resolveOAuthTokens(params: {
|
||||||
provider: UsageProviderId;
|
provider: UsageProviderId;
|
||||||
agentDir?: string;
|
agentDir?: string;
|
||||||
}): Promise<ProviderAuth | null> {
|
}): Promise<ProviderAuth[]> {
|
||||||
const cfg = loadConfig();
|
const cfg = loadConfig();
|
||||||
const store = ensureAuthProfileStore(params.agentDir, {
|
const store = ensureAuthProfileStore(params.agentDir, {
|
||||||
allowKeychainPrompt: false,
|
allowKeychainPrompt: false,
|
||||||
@ -143,6 +143,7 @@ async function resolveOAuthToken(params: {
|
|||||||
if (!deduped.includes(entry)) deduped.push(entry);
|
if (!deduped.includes(entry)) deduped.push(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const results: ProviderAuth[] = [];
|
||||||
for (const profileId of deduped) {
|
for (const profileId of deduped) {
|
||||||
const cred = store.profiles[profileId];
|
const cred = store.profiles[profileId];
|
||||||
if (!cred || (cred.type !== "oauth" && cred.type !== "token")) continue;
|
if (!cred || (cred.type !== "oauth" && cred.type !== "token")) continue;
|
||||||
@ -161,20 +162,20 @@ async function resolveOAuthToken(params: {
|
|||||||
const parsed = parseGoogleToken(resolved.apiKey);
|
const parsed = parseGoogleToken(resolved.apiKey);
|
||||||
token = parsed?.token ?? resolved.apiKey;
|
token = parsed?.token ?? resolved.apiKey;
|
||||||
}
|
}
|
||||||
return {
|
results.push({
|
||||||
provider: params.provider,
|
provider: params.provider,
|
||||||
token,
|
token,
|
||||||
accountId:
|
accountId:
|
||||||
cred.type === "oauth" && "accountId" in cred
|
cred.type === "oauth" && "accountId" in cred
|
||||||
? (cred as { accountId?: string }).accountId
|
? (cred as { accountId?: string }).accountId
|
||||||
: undefined,
|
: undefined,
|
||||||
};
|
});
|
||||||
} catch {
|
} catch {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveOAuthProviders(agentDir?: string): UsageProviderId[] {
|
function resolveOAuthProviders(agentDir?: string): UsageProviderId[] {
|
||||||
@ -233,11 +234,11 @@ export async function resolveProviderAuths(params: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!oauthProviders.includes(provider)) continue;
|
if (!oauthProviders.includes(provider)) continue;
|
||||||
const auth = await resolveOAuthToken({
|
const resolved = await resolveOAuthTokens({
|
||||||
provider,
|
provider,
|
||||||
agentDir: params.agentDir,
|
agentDir: params.agentDir,
|
||||||
});
|
});
|
||||||
if (auth) auths.push(auth);
|
auths.push(...resolved);
|
||||||
}
|
}
|
||||||
|
|
||||||
return auths;
|
return auths;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user