Skip to content

Commit be0039d

Browse files
committed
fix(auth): clear stale failure counters on token rotation
Delete prior refresh-token failure state when updateFromAuth rotates tokens, and add regression coverage.
1 parent c6531ab commit be0039d

File tree

2 files changed

+35
-0
lines changed

2 files changed

+35
-0
lines changed

lib/accounts.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,9 +758,13 @@ export class AccountManager {
758758
}
759759

760760
updateFromAuth(account: ManagedAccount, auth: OAuthAuthDetails): void {
761+
const previousRefreshToken = account.refreshToken;
761762
account.refreshToken = auth.refresh;
762763
account.access = auth.access;
763764
account.expires = auth.expires;
765+
if (previousRefreshToken !== account.refreshToken) {
766+
this.authFailuresByRefreshToken.delete(previousRefreshToken);
767+
}
764768
const tokenAccountId = extractAccountId(auth.access);
765769
if (
766770
tokenAccountId &&

test/accounts.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,6 +1064,37 @@ describe("AccountManager", () => {
10641064
expect(account.accountId).toBe("org-selected-id");
10651065
expect(account.accountIdSource).toBe("org");
10661066
});
1067+
1068+
it("clears stale auth failure state when refresh token rotates", () => {
1069+
const now = Date.now();
1070+
const stored = {
1071+
version: 3 as const,
1072+
activeIndex: 0,
1073+
accounts: [
1074+
{ refreshToken: "old-token", addedAt: now, lastUsed: now },
1075+
],
1076+
};
1077+
1078+
const manager = new AccountManager(undefined, stored);
1079+
const account = manager.getCurrentAccount()!;
1080+
expect(manager.incrementAuthFailures(account)).toBe(1);
1081+
1082+
const newAuth: OAuthAuthDetails = {
1083+
type: "oauth",
1084+
access: "new-access",
1085+
refresh: "new-refresh",
1086+
expires: now + 3600000,
1087+
};
1088+
1089+
manager.updateFromAuth(account, newAuth);
1090+
1091+
const failuresByRefreshToken = Reflect.get(
1092+
manager,
1093+
"authFailuresByRefreshToken",
1094+
) as Map<string, number>;
1095+
expect(failuresByRefreshToken.has("old-token")).toBe(false);
1096+
expect(manager.incrementAuthFailures(account)).toBe(1);
1097+
});
10671098
});
10681099

10691100
describe("toAuthDetails", () => {

0 commit comments

Comments
 (0)