@modelprofile.com/authswitch 5.2.0 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist_ts/00_commitinfo_data.js +3 -3
  2. package/dist_ts/accounts.js +3 -2
  3. package/dist_ts/classes.claudecodeharness.d.ts +13 -4
  4. package/dist_ts/classes.claudecodeharness.js +36 -11
  5. package/dist_ts/classes.claudestatus.d.ts +25 -5
  6. package/dist_ts/classes.claudestatus.js +25 -20
  7. package/dist_ts/classes.claudetokenrefresh.d.ts +38 -3
  8. package/dist_ts/classes.claudetokenrefresh.js +80 -21
  9. package/dist_ts/classes.cli.js +3 -3
  10. package/dist_ts/classes.credentialstore.d.ts +3 -1
  11. package/dist_ts/classes.credentialstore.js +2 -2
  12. package/dist_ts/classes.fileharness.d.ts +16 -5
  13. package/dist_ts/classes.fileharness.js +31 -9
  14. package/dist_ts/classes.opencodeanthropicrefresh.d.ts +29 -0
  15. package/dist_ts/classes.opencodeanthropicrefresh.js +59 -0
  16. package/dist_ts/classes.opencodeharness.d.ts +40 -0
  17. package/dist_ts/classes.opencodeharness.js +100 -3
  18. package/dist_ts/claudehttp.d.ts +14 -0
  19. package/dist_ts/claudehttp.js +21 -1
  20. package/dist_ts/interfaces.harness.d.ts +7 -3
  21. package/package.json +1 -1
  22. package/readme.md +89 -23
  23. package/ts/00_commitinfo_data.ts +3 -3
  24. package/ts/accounts.ts +2 -1
  25. package/ts/classes.claudecodeharness.ts +37 -12
  26. package/ts/classes.claudestatus.ts +39 -19
  27. package/ts/classes.claudetokenrefresh.ts +96 -20
  28. package/ts/classes.cli.ts +3 -3
  29. package/ts/classes.credentialstore.ts +2 -2
  30. package/ts/classes.fileharness.ts +28 -8
  31. package/ts/classes.opencodeanthropicrefresh.ts +64 -0
  32. package/ts/classes.opencodeharness.ts +97 -2
  33. package/ts/claudehttp.ts +22 -0
  34. package/ts/interfaces.harness.ts +7 -3
@@ -2,10 +2,18 @@ import * as plugins from './plugins.js';
2
2
  import { FileHarness } from './classes.fileharness.js';
3
3
  import { CredentialStore, credentialHash, credentialRecord, credentialText, readCredentialDocument, readCredentialRaw } from './classes.credentialstore.js';
4
4
  import { HarnessProcesses } from './classes.harnessprocesses.js';
5
+ import { ClaudeAccountStatus } from './classes.claudestatus.js';
6
+ import { CLAUDE_REFRESH_MARGIN_MS } from './classes.claudetokenrefresh.js';
7
+ import { ClaudeLoginRejectedError, ClaudeRateLimitError } from './claudehttp.js';
5
8
  import { CodexAccountStatus } from './classes.codexstatus.js';
9
+ import { OpenCodeAnthropicRefresh } from './classes.opencodeanthropicrefresh.js';
6
10
  import { writeSecretFileAtomically } from './helpers.js';
7
11
  import { beginSavedOpenAiLogin, openCodeCredentialFromLogin } from './classes.login.js';
8
12
  import { plainText } from './formatting.js';
13
+ /** Anthropic refused the grant OpenCode's entry holds; no retry and no other account changes that answer. */
14
+ const ANTHROPIC_LOGIN_REJECTED = 'Login expired or was rejected. Log in again with opencode auth login.';
15
+ /** A saved copy is not the login OpenCode uses, so renewing it would rotate a token OpenCode's own entry still holds. */
16
+ const SAVED_ANTHROPIC_EXPIRED = 'This saved Anthropic login\'s access token has expired. authswitch renews the Anthropic login OpenCode has active; activate this one to have it renewed, or log in again with opencode auth login.';
9
17
  /** OpenCode owns one login per provider. Replacing a slot never replaces the whole provider set. */
10
18
  export class OpenCodeHarness extends FileHarness {
11
19
  id = 'opencode';
@@ -15,20 +23,30 @@ export class OpenCodeHarness extends FileHarness {
15
23
  liveSwap = false;
16
24
  /** Only its OpenAI login reports usage, and a supervisor (AGL) restarts it around a switch, so a watch leaves it alone. */
17
25
  autoSwitch = false;
26
+ /** OpenCode re-reads its credential file on every request; only a request already in flight still holds the previous login. */
27
+ runningRetention() {
28
+ return 'They re-read the credential file on every request, but a request already in flight still holds the previous login, and its token refresh can ';
29
+ }
18
30
  loginProviders = [{ providerId: 'openai', label: 'OpenAI', flows: ['device'] }];
19
31
  store;
20
32
  file;
21
33
  env;
22
34
  status;
35
+ claudeStatus;
36
+ anthropicRefresh;
23
37
  processes;
24
38
  fetcher;
39
+ now;
25
40
  constructor(options = {}) {
26
41
  super();
27
42
  this.env = options.env ?? process.env;
28
43
  this.file = plugins.path.join(options.dataHome ?? (this.env.XDG_DATA_HOME || plugins.path.join(plugins.os.homedir(), '.local', 'share')), 'opencode', 'auth.json');
29
44
  this.store = new CredentialStore(this.id, options.stashRoot);
30
45
  this.status = new CodexAccountStatus(options.fetch);
46
+ this.claudeStatus = new ClaudeAccountStatus(options.fetch, options.now);
47
+ this.anthropicRefresh = new OpenCodeAnthropicRefresh(options.fetch, options.now);
31
48
  this.fetcher = options.fetch;
49
+ this.now = options.now ?? Date.now;
32
50
  this.processes = options.processes ?? new HarnessProcesses('opencode');
33
51
  }
34
52
  /** Every provider entry lives in one file, so its bytes are the whole stability proof. */
@@ -113,14 +131,93 @@ export class OpenCodeHarness extends FileHarness {
113
131
  if (readCredentialDocument(this.file).raw !== raw)
114
132
  throw new Error('Active login verification failed. The outgoing login remains saved.');
115
133
  }
116
- async readAccountStatus(id, optionsArg) {
117
- const account = this.readCredential(id);
134
+ /** The login OpenCode has in a provider slot, read from its file; undefined where the file holds none it can read. */
135
+ activeSlot(slotIdArg) {
136
+ return this.snapshot().accounts.find(account => account.slotId === slotIdArg);
137
+ }
138
+ /** Whether this login's access token is inside Claude Code's five-minute margin, the margin Claude's own logins use. */
139
+ renewalDue(credentialArg) {
140
+ const expires = credentialArg.expires;
141
+ return typeof expires === 'number' && Number.isFinite(expires) && this.now() + CLAUDE_REFRESH_MARGIN_MS >= expires;
142
+ }
143
+ /**
144
+ * Renews OpenCode's active Anthropic login and writes the rotated pair back into OpenCode's own credential file.
145
+ *
146
+ * Nothing is stranded by that write. OpenCode's auth service reads `auth.json` on every `Auth.all()`, `Auth.get()`
147
+ * is that read (1.18.15 @99100961, 1.18.31 @103733929), and its Anthropic provider -- `opencode-anthropic-auth`
148
+ * 0.0.13, since the binary carries no Anthropic OAuth code -- calls the `getAuth()` it was initialised with
149
+ * (@98017331) inside the `fetch` wrapper of every single request. A running OpenCode therefore holds no refresh
150
+ * token in memory and picks up this rotation on its next request, exactly as it picks up its own.
151
+ *
152
+ * The renewal is the only authswitch operation on the store while it runs, and the rotated pair replaces the
153
+ * entry only while OpenCode still holds the refresh token that was sent: a login OpenCode renewed meanwhile is
154
+ * returned as it now stands. The write itself is `apply`'s verified compare-and-swap, which preserves every other
155
+ * provider and replaces the file atomically -- OpenCode writes the same file in place. The slot's switch record
156
+ * follows that write, because an `anthropic` login's identity is its refresh token and this rotation is
157
+ * authswitch's own: without that, the next read would report this write as a different account.
158
+ */
159
+ renewAnthropic(accountArg, signalArg) {
160
+ return this.store.locked(async () => {
161
+ const current = this.activeSlot(accountArg.slotId) ?? accountArg;
162
+ if (!this.renewalDue(current.credential))
163
+ return current;
164
+ const refreshToken = credentialText(current.credential.refresh);
165
+ if (refreshToken === undefined)
166
+ throw new Error('This Anthropic login holds no refresh token; log in again with opencode auth login.');
167
+ signalArg?.throwIfAborted();
168
+ const tokens = await this.anthropicRefresh.refresh(refreshToken);
169
+ const latest = this.activeSlot(accountArg.slotId);
170
+ if (!latest || credentialText(latest.credential.refresh) !== refreshToken)
171
+ return latest ?? current;
172
+ const renewed = this.inspect({ ...latest.credential, access: tokens.access, refresh: tokens.refresh, expires: tokens.expires }, latest.slotId);
173
+ this.apply(latest.slotId, latest, renewed);
174
+ this.recordRenewal(latest.slotId);
175
+ return renewed;
176
+ }, { signal: signalArg });
177
+ }
178
+ /**
179
+ * The subscription and usage of an OpenCode `anthropic` OAuth login.
180
+ *
181
+ * That entry holds the same Claude subscriber grant Claude Code stores, so Claude's own account endpoints answer
182
+ * for it and the account reports real windows instead of no quota API at all. OpenCode keeps no scopes and no
183
+ * account identity with it, so the service decides both. A due access token is renewed first, with OpenCode's own
184
+ * request; a refusal is reported and nothing is written, so the entry OpenCode owns is left exactly as it was.
185
+ *
186
+ * A saved copy is never renewed: OpenCode's entry holds the same refresh token, and rotating it here would leave
187
+ * the login OpenCode actually uses holding a token the service has replaced.
188
+ */
189
+ async anthropicStatus(accountArg, isActiveArg, optionsArg) {
190
+ let account = accountArg;
191
+ if (this.renewalDue(account.credential)) {
192
+ if (!isActiveArg)
193
+ return this.claudeStatus.unavailable({}, SAVED_ANTHROPIC_EXPIRED);
194
+ try {
195
+ account = await this.renewAnthropic(account, optionsArg.signal);
196
+ }
197
+ catch (error) {
198
+ if (optionsArg.signal?.aborted)
199
+ throw error;
200
+ const problem = error instanceof ClaudeLoginRejectedError ? ANTHROPIC_LOGIN_REJECTED
201
+ : error instanceof Error ? error.message : 'the login could not be renewed.';
202
+ return this.claudeStatus.unavailable({}, `Login refresh: ${problem}`, error instanceof ClaudeRateLimitError ? { retryAt: error.retryAt } : undefined);
203
+ }
204
+ }
205
+ const accessToken = credentialText(account.credential.access);
206
+ if (accessToken === undefined)
207
+ return this.claudeStatus.unavailable({}, 'This Anthropic login holds no usable access token; log in again with opencode auth login.');
208
+ return this.claudeStatus.read({ accessToken, scopes: [] }, optionsArg);
209
+ }
210
+ async readAccountStatus(id, optionsArg = {}) {
211
+ const active = this.activeCredential(id);
212
+ const account = active ?? this.savedCredential(id);
118
213
  if (account.slotId === 'openai' && account.credential.type === 'oauth') {
119
214
  const info = this.openAiInfo(account.credential);
120
215
  if (!info.accountId)
121
216
  return { facts: [], problems: ['The OpenAI login has no account ID for a status lookup.'] };
122
217
  return this.status.readCredential(credentialText(account.credential.access), info.accountId, info.plan, optionsArg);
123
218
  }
219
+ if (account.slotId === 'anthropic' && account.credential.type === 'oauth')
220
+ return this.anthropicStatus(account, active !== undefined, optionsArg);
124
221
  return { facts: [
125
222
  { section: 'Authentication', label: 'Provider', value: account.slotId },
126
223
  { section: 'Authentication', label: 'Login type', value: String(account.credential.type) },
@@ -128,4 +225,4 @@ export class OpenCodeHarness extends FileHarness {
128
225
  ], problems: [] };
129
226
  }
130
227
  }
131
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5vcGVuY29kZWhhcm5lc3MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLm9wZW5jb2RlaGFybmVzcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEVBQUUsV0FBVyxFQUFnRCxNQUFNLDBCQUEwQixDQUFDO0FBQ3JHLE9BQU8sRUFBRSxlQUFlLEVBQUUsY0FBYyxFQUFFLGdCQUFnQixFQUFFLGNBQWMsRUFBRSxzQkFBc0IsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQzVKLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQ2pFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQzlELE9BQU8sRUFBRSx5QkFBeUIsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUV6RCxPQUFPLEVBQUUscUJBQXFCLEVBQUUsMkJBQTJCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUN4RixPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFXNUMsb0dBQW9HO0FBQ3BHLE1BQU0sT0FBTyxlQUFnQixTQUFRLFdBQVc7SUFDOUIsRUFBRSxHQUFHLFVBQVUsQ0FBQztJQUNoQixLQUFLLEdBQUcsVUFBVSxDQUFDO0lBQ25CLFNBQVMsR0FBRyx3RkFBd0YsQ0FBQztJQUNySCx1SEFBdUg7SUFDdkcsUUFBUSxHQUFHLEtBQUssQ0FBQztJQUNqQywySEFBMkg7SUFDM0csVUFBVSxHQUFHLEtBQUssQ0FBQztJQUNuQixjQUFjLEdBQTRCLENBQUMsRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3RHLEtBQUssQ0FBa0I7SUFDekIsSUFBSSxDQUFTO0lBQ2IsR0FBRyxD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
228
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5vcGVuY29kZWhhcm5lc3MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLm9wZW5jb2RlaGFybmVzcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEVBQUUsV0FBVyxFQUFnRCxNQUFNLDBCQUEwQixDQUFDO0FBQ3JHLE9BQU8sRUFBRSxlQUFlLEVBQUUsY0FBYyxFQUFFLGdCQUFnQixFQUFFLGNBQWMsRUFBRSxzQkFBc0IsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQzVKLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQ2pFLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ2hFLE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQzNFLE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxvQkFBb0IsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ2pGLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQzlELE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLHVDQUF1QyxDQUFDO0FBQ2pGLE9BQU8sRUFBRSx5QkFBeUIsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUV6RCxPQUFPLEVBQUUscUJBQXFCLEVBQUUsMkJBQTJCLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUN4RixPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFhNUMsNkdBQTZHO0FBQzdHLE1BQU0sd0JBQXdCLEdBQUcsdUVBQXVFLENBQUM7QUFDekcseUhBQXlIO0FBQ3pILE1BQU0sdUJBQXVCLEdBQUcsb01BQW9NLENBQUM7QUFFck8sb0dBQW9HO0FBQ3BHLE1BQU0sT0FBTyxlQUFnQixTQUFRLFdBQVc7SUFDOUIsRUFBRSxHQUFHLFVBQVUs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
@@ -7,6 +7,20 @@ export declare const CLAUDE_LOGIN_REJECTED = "Login expired or was rejected. Log
7
7
  export declare class ClaudeLoginRejectedError extends ClaudeRequestError {
8
8
  constructor();
9
9
  }
10
+ /**
11
+ * Where Claude Code 2.1.273 sends an account the service put on hold (`T5e`, bundle offset @190070402). A hold is
12
+ * not a dead login: the service refuses the grant while it lasts and accepts it again once it is lifted.
13
+ */
14
+ export declare const CLAUDE_ACCOUNT_ON_HOLD_URL = "https://claude.ai/restricted";
15
+ /** The service put this account on hold. The login itself is intact, so it is never remembered as refused. */
16
+ export declare class ClaudeAccountOnHoldError extends ClaudeRequestError {
17
+ constructor();
18
+ }
19
+ /**
20
+ * The OAuth error code a response names, read as Claude Code 2.1.273 reads it (`xc`, @191165290): the `error` field
21
+ * as a string, or the `type` of the object some Anthropic endpoints send it as.
22
+ */
23
+ export declare const oauthErrorCode: (bodyArg: Record<string, unknown> | null) => string | undefined;
10
24
  /** The service refused a request for too many requests. That says nothing about the account's usage or login. */
11
25
  export declare class ClaudeRateLimitError extends ClaudeRequestError {
12
26
  readonly retryAt: string | null;
@@ -10,6 +10,26 @@ export const CLAUDE_LOGIN_REJECTED = 'Login expired or was rejected. Log in agai
10
10
  export class ClaudeLoginRejectedError extends ClaudeRequestError {
11
11
  constructor() { super(CLAUDE_LOGIN_REJECTED); }
12
12
  }
13
+ /**
14
+ * Where Claude Code 2.1.273 sends an account the service put on hold (`T5e`, bundle offset @190070402). A hold is
15
+ * not a dead login: the service refuses the grant while it lasts and accepts it again once it is lifted.
16
+ */
17
+ export const CLAUDE_ACCOUNT_ON_HOLD_URL = 'https://claude.ai/restricted';
18
+ /** The service put this account on hold. The login itself is intact, so it is never remembered as refused. */
19
+ export class ClaudeAccountOnHoldError extends ClaudeRequestError {
20
+ constructor() { super(`This Claude account is on hold and cannot sign in. View details or appeal: ${CLAUDE_ACCOUNT_ON_HOLD_URL}`); }
21
+ }
22
+ /**
23
+ * The OAuth error code a response names, read as Claude Code 2.1.273 reads it (`xc`, @191165290): the `error` field
24
+ * as a string, or the `type` of the object some Anthropic endpoints send it as.
25
+ */
26
+ export const oauthErrorCode = (bodyArg) => {
27
+ const error = bodyArg?.error;
28
+ if (typeof error === 'string')
29
+ return error;
30
+ const type = typeof error === 'object' && error !== null ? error.type : undefined;
31
+ return typeof type === 'string' ? type : undefined;
32
+ };
13
33
  /** The service refused a request for too many requests. That says nothing about the account's usage or login. */
14
34
  export class ClaudeRateLimitError extends ClaudeRequestError {
15
35
  retryAt;
@@ -80,4 +100,4 @@ export const claudeRequest = async (fetcherArg, requestArg) => {
80
100
  throw new ClaudeRequestError(`The ${requestArg.subject} service could not be reached.`);
81
101
  }
82
102
  };
83
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhdWRlaHR0cC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2NsYXVkZWh0dHAudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3JELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ2hFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUU3QyxtSEFBbUg7QUFDbkgsTUFBTSxPQUFPLGtCQUFtQixTQUFRLEtBQUs7Q0FBRztBQUVoRCxzSEFBc0g7QUFDdEgsTUFBTSxDQUFDLE1BQU0scUJBQXFCLEdBQUcsMkVBQTJFLENBQUM7QUFFakgsNENBQTRDO0FBQzVDLE1BQU0sT0FBTyx3QkFBeUIsU0FBUSxrQkFBa0I7SUFDOUQsZ0JBQWdCLEtBQUssQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLENBQUMsQ0FBQztDQUNoRDtBQUVELGlIQUFpSDtBQUNqSCxNQUFNLE9BQU8sb0JBQXFCLFNBQVEsa0JBQWtCO0lBQ1Y7SUFBaEQsWUFBWSxVQUFrQixFQUFrQixPQUFzQjtRQUNwRSxLQUFLLENBQUMsT0FBTyxVQUFVLGlFQUFpRSxDQUFDLENBQUM7UUFENUMsWUFBTyxHQUFQLE9BQU8sQ0FBZTtJQUV0RSxDQUFDO0NBQ0Y7QUF1QkQsTUFBTSxrQkFBa0IsR0FBRyxJQUFJLEdBQUcsSUFBSSxDQUFDO0FBRXZDLG9HQUFvRztBQUNwRyxNQUFNLFFBQVEsR0FBRyxLQUFLLEVBQUUsV0FBcUIsRUFBRSxVQUFrQixFQUEyQyxFQUFFO0lBQzVHLE1BQU0sTUFBTSxHQUFHLFdBQVcsQ0FBQyxJQUFJLEVBQUUsU0FBUyxFQUFFLENBQUM7SUFDN0MsSUFBSSxDQUFDLE1BQU07UUFBRSxPQUFPLElBQUksQ0FBQztJQUN6QixNQUFNLE1BQU0sR0FBaUIsRUFBRSxDQUFDO0lBQ2hDLElBQUksSUFBSSxHQUFHLENBQUMsQ0FBQztJQUNiLElB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
103
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhdWRlaHR0cC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2NsYXVkZWh0dHAudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3JELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ2hFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUU3QyxtSEFBbUg7QUFDbkgsTUFBTSxPQUFPLGtCQUFtQixTQUFRLEtBQUs7Q0FBRztBQUVoRCxzSEFBc0g7QUFDdEgsTUFBTSxDQUFDLE1BQU0scUJBQXFCLEdBQUcsMkVBQTJFLENBQUM7QUFFakgsNENBQTRDO0FBQzVDLE1BQU0sT0FBTyx3QkFBeUIsU0FBUSxrQkFBa0I7SUFDOUQsZ0JBQWdCLEtBQUssQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLENBQUMsQ0FBQztDQUNoRDtBQUVEOzs7R0FHRztBQUNILE1BQU0sQ0FBQyxNQUFNLDBCQUEwQixHQUFHLDhCQUE4QixDQUFDO0FBRXpFLDhHQUE4RztBQUM5RyxNQUFNLE9BQU8sd0JBQXlCLFNBQVEsa0JBQWtCO0lBQzlELGdCQUFnQixLQUFLLENBQUMsOEVBQThFLDBCQUEwQixFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7Q0FDckk7QUFFRDs7O0dBR0c7QUFDSCxNQUFNLENBQUMsTUFBTSxjQUFjLEdBQUcsQ0FBQyxPQUF1QyxFQUFzQixFQUFFO0lBQzVGLE1BQU0sS0FBSyxHQUFHLE9BQU8sRUFBRSxLQUFLLENBQUM7SUFDN0IsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRO1FBQUUsT0FBTyxLQUFLLENBQUM7SUFDNUMsTUFBTSxJQUFJLEdBQUcsT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLEtBQUssS0FBSyxJQUFJLENBQUMsQ0FBQyxDQUFFLEtBQWlDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7SUFD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
@@ -236,9 +236,13 @@ export interface IAuthHarness {
236
236
  */
237
237
  readonly autoSwitch?: boolean;
238
238
  /**
239
- * The account's live status. It must never activate, switch or clear a login. It may renew the tokens of the
240
- * saved copy it reads when the provider leaves it no other way to answer -- the Claude Code adapter does, for
241
- * saved and inactive logins only, under its store's lock -- and must leave the active login's credential alone.
239
+ * The account's live status. It must never activate, switch or clear a login.
240
+ *
241
+ * It may renew the tokens of the credential it reads when the provider leaves it no other way to answer, under
242
+ * its store's lock and with a compare-and-swap on the refresh token it sent. A saved copy is always its own to
243
+ * renew -- the Claude Code adapter renews one, because Claude Code's active login is Claude Code's. The active
244
+ * login may only be renewed where the owning harness re-reads its credential file on every request, so that the
245
+ * rotation strands nothing: OpenCode's Anthropic provider does, and authswitch renews that entry.
242
246
  */
243
247
  readAccountStatus(accountIdArg: string, optionsArg?: IHarnessStatusOptions): Promise<IHarnessAccountStatus>;
244
248
  readonly loginProviders?: IHarnessLoginProvider[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@modelprofile.com/authswitch",
3
- "version": "5.2.0",
3
+ "version": "6.1.0",
4
4
  "private": false,
5
5
  "description": "Manage Codex, OpenCode and Claude Code accounts with guided switching and live usage status",
6
6
  "main": "dist_ts/index.js",
package/readme.md CHANGED
@@ -109,8 +109,11 @@ never blocked by a waiting switch; after that the operation fails with nothing
109
109
  changed. A lock left behind by a Claude Code that died goes stale after its own
110
110
  threshold and is taken over, as Claude Code itself would.
111
111
 
112
- **OpenCode keeps the previous login until it restarts.** It holds that login in
113
- memory and can write it back at its next OAuth token refresh. So before `use` and
112
+ **A running OpenCode can still overwrite a switch.** Not by holding the previous login:
113
+ its auth service caches nothing and re-reads `auth.json` on every lookup. The window is a
114
+ request already in flight, which read the previous login before the switch and can write
115
+ that login's own rotation back afterwards -- and OpenCode replaces the whole provider map
116
+ in place rather than atomically. So before `use` and
114
117
  before `stash` without `--keep`, authswitch lists OpenCode's own running instances --
115
118
  pid, start time and command line -- and offers to stop them:
116
119
 
@@ -214,8 +217,20 @@ every other provider, and `stash openai` without `--keep` clears only OpenAI.
214
217
  When several logins are active, the guide asks which to save; scripts must name
215
218
  the provider or account. In the TUI, select an active row before pressing `a` or `c`.
216
219
  ChatGPT OAuth accounts display their email and use the same direct status APIs as
217
- Codex. API keys and opaque provider tokens have no reliable email, so their labels
218
- contain the provider and a SHA-256 fingerprint. Their quota/billing information is
220
+ Codex. An `anthropic` OAuth login holds the same Claude subscriber grant Claude Code
221
+ stores, so it reports Claude's own plan, organization and usage windows through the
222
+ account endpoints described under **Claude Code**; OpenCode keeps no scopes and no
223
+ account identity with that entry, so both are left to the service. An access token inside
224
+ Claude Code's five-minute margin is renewed first, with the request OpenCode's own
225
+ Anthropic provider sends (`opencode-anthropic-auth`: `console.anthropic.com`, Claude
226
+ Code's public client, no scope), and the rotated pair is written back into `auth.json`
227
+ atomically, preserving every other provider. Nothing is stranded by that write: OpenCode's
228
+ auth service re-reads `auth.json` on every lookup and its Anthropic provider asks for the
229
+ credential again inside every request, so a running instance picks up the rotation exactly
230
+ as it picks up its own. A refusal is reported and nothing is written, and a saved copy is
231
+ never renewed, because OpenCode's own entry holds the same refresh token.
232
+ API keys and opaque provider tokens have no reliable email, so their
233
+ labels contain the provider and a SHA-256 fingerprint. Their quota/billing information is
219
234
  explicitly unavailable. `OPENCODE_AUTH_CONTENT` overrides the file and blocks file
220
235
  management. Provider configuration and environment credentials remain managed by OpenCode.
221
236
 
@@ -254,19 +269,27 @@ authswitch does not infer them from account creation or token expiry dates. The
254
269
  Claude Code adapter declares that, so `limits` explains it once for the provider
255
270
  instead of per account.
256
271
 
257
- Nothing but Claude Code refreshes a Claude login, so a saved one stops being readable
258
- a few hours after it was saved. Reading a **saved, inactive** account's status therefore
272
+ Nothing but Claude Code refreshes a Claude login, so a saved one stops being readable a
273
+ few hours after it was saved. Reading a **saved, inactive** account's status therefore
259
274
  refreshes it first, exactly as Claude Code would: when its access token expires within
260
275
  five minutes, authswitch exchanges the stored refresh token at Claude's token endpoint,
261
276
  keeps every other field of the login, and writes the result only while the saved record
262
- still holds the refresh token it sent. The refresh holds the account store's lock, so a
263
- switch started at the same time waits for it and then activates the refreshed login. The
264
- **active** login is never refreshed -- Claude Code owns it, and two parties refreshing one
265
- login can invalidate the grant. A refusal is reported, never worked around -- a rejected
266
- grant says so and says what fixes it (below), and a service failure, an unreachable service
267
- or an unsupported response leave the saved login untouched. Requests carry `User-Agent:
268
- authswitch/<version>`, and HTTP 429 is reported as rate limiting with the service's retry
269
- time -- never as an exhausted or expired account.
277
+ still holds the refresh token it sent. The request is the one Claude Code sends, down to
278
+ the scopes: a login of Claude Code's own OAuth client is renewed with Claude Code's
279
+ current scope set plus the project scopes the login carries -- not with the set the
280
+ login happens to be stored under, which can be an older or wider one the service no
281
+ longer accepts -- and a set the service refuses as `invalid_scope` is sent once more
282
+ with the stored scopes. A login that names its own OAuth client keeps its stored scopes,
283
+ because only that client's grant knows them. A login that is neither one of Claude
284
+ Code's subscriber logins nor stored with a plan is not sent at all. The refresh holds
285
+ the account store's lock, so a switch started at the same time waits for it and then
286
+ activates the refreshed login. The **active** login is never refreshed -- Claude Code
287
+ owns it, and two parties refreshing one login can invalidate the grant. A refusal is
288
+ reported, never worked around -- a rejected grant says so and says what fixes it
289
+ (below), and a service failure, an unreachable service or an unsupported response leave
290
+ the saved login untouched. Requests carry `User-Agent: authswitch/<version>`, and HTTP
291
+ 429 is reported as rate limiting with the service's retry time -- never as an exhausted
292
+ or expired account.
270
293
 
271
294
  Claude Code also rotates the refresh token of the login it **is** running on, so reading the
272
295
  accounts (`list`, `limits`, `active`, `current`, `watch`, the dashboard) mirrors that login
@@ -279,14 +302,57 @@ saved implicitly; `stash` is what saves a login. An installation whose native lo
279
302
  authswitch cannot read mirrors nothing, and a read waits at most a second for a lock a
280
303
  switch or Claude Code holds before leaving the saved copy to the next read.
281
304
 
282
- A grant the sign-in service refused is remembered in the saved record itself, as a hash of
283
- the refresh token -- never the token -- so a new authswitch run, a restarted watch or a
284
- second dashboard does not replay a dead login. Saving that login again clears it, as does
285
- any refresh that replaces the saved credential. Such a login reports `Login expired or was
286
- rejected. Log in again with Claude Code and save it. Claude Code rotates a login's refresh
287
- token as it uses it, and the service can refuse the older one a saved copy still holds once
288
- that login has been replaced outside authswitch; authswitch claude stash --keep saves the
289
- new one.`
305
+ An account the service has put **on hold** is not a dead login: the hold refuses the grant
306
+ while it lasts and the same login works again once it is lifted, so such an account keeps
307
+ its stored plan, says that it is on hold and where to appeal, and is asked again on the
308
+ next read.
309
+
310
+ A grant the sign-in service refused is remembered in the saved record itself, as a hash
311
+ of the request that was refused -- the refresh token, the client and the scopes, never
312
+ the token itself -- so a new authswitch run, a restarted watch or a second dashboard
313
+ does not replay a dead login. Because the hash covers the request and not only the
314
+ token, a release that changes how authswitch asks gives every such login one honest
315
+ attempt under the new derivation, while a refusal of the request authswitch still sends
316
+ stays remembered. Saving that login again clears it, as does any refresh that replaces
317
+ the saved credential. Such a login reports `Login expired or was rejected. Log in again
318
+ with Claude Code and save it. Claude Code rotates a login's refresh token as it uses it,
319
+ and the service can refuse the older one a saved copy still holds once that login has
320
+ been replaced outside authswitch; authswitch claude stash --keep saves the new one.`
321
+
322
+ Each `n/a` in a Claude row has a reason in the footnote under the table, and each
323
+ reason names what to do:
324
+
325
+ - `Login refresh: Login expired or was rejected.` -- the sign-in service refused the
326
+ saved refresh token itself. Log in again in Claude Code for that account and run
327
+ `authswitch claude stash --keep`; nothing else fixes it.
328
+ - `Login refresh: This Claude account is on hold and cannot sign in.` -- the account,
329
+ not the login. Appeal at the address in the message; the saved login is kept and is
330
+ asked again on the next read.
331
+ - `Login refresh: This saved login has no refresh token, and no subscriber scope or
332
+ plan to refresh with.` -- the saved record is missing what a refresh is made of.
333
+ Save the login again.
334
+ - `Login refresh: this saved login's access token has expired and cannot be renewed
335
+ for this installation.` -- authswitch cannot read Claude Code's own files here (the
336
+ macOS Keychain, or an incomplete native login), so it cannot prove this login is not
337
+ the active one, and never refreshes a login that might be.
338
+ - `Login refresh: The Claude sign-in service returned HTTP ...`, `... could not be
339
+ reached.`, `... timed out.`, `... is rate limiting requests (HTTP 429)` -- the
340
+ service, not the login. The saved login is untouched; read again later.
341
+ - `Profile: ...` or `Usage: ...` -- the account endpoints, asked with a token the
342
+ refresh had just accepted. `Profile: Login expired or was rejected.` means the access
343
+ token itself was refused; the other wordings are the service, as above.
344
+ - `Claude returned a different account or organization` -- the answer was about another
345
+ account and was discarded whole, rather than shown under this account's name.
346
+ - `Claude profile response is unsupported` or `Claude usage response is unsupported` --
347
+ the service answered in a shape authswitch does not read. Nothing is guessed from a
348
+ response it does not understand.
349
+
350
+ An OpenCode `anthropic` row reads the same endpoints and so shows the same reasons. Its
351
+ renewal adds `Login refresh: Login expired or was rejected. Log in again with opencode
352
+ auth login.`, which is Anthropic refusing the refresh token OpenCode's entry holds -- no
353
+ retry changes that, and the refusal is never remembered, because OpenCode owns that entry.
354
+ `This saved Anthropic login's access token has expired.` is a stashed copy, which is left
355
+ alone so that the login OpenCode uses keeps a refresh token the service still accepts.
290
356
 
291
357
  OpenCode and Claude saved records are separate owner-only files under
292
358
  `~/.authswitch/opencode` and `~/.authswitch/claude`. Emails are accepted as account
@@ -982,7 +1048,7 @@ Account identity comes from the `id_token` inside the credential — the email c
982
1048
 
983
1049
  **Other Codex clients keep running.** Stopping the managed app-server does not stop an editor extension that spawned its own. Close it, or expect it to keep using the credential it already loaded.
984
1050
 
985
- **A running OpenCode can undo a switch.** It holds the previous login in memory and rewrites the credential file at its next token refresh. Authswitch lists those instances, offers to stop them, warns when any keep running, and detects the overwrite afterwards — but it cannot prevent it while they run. Restart them after a switch. A running Claude Code picks the switch up instead; its guarantee rests on the behaviour and lock protocol verified against Claude Code 2.1.273, and `authswitch claude active` still reports a login that changed outside authswitch.
1051
+ **A running OpenCode can undo a switch.** Its auth service keeps no login in memory -- every lookup re-reads `auth.json` -- but a request already in flight, which read the previous login before the switch, can write that login's own rotation back afterwards, over a provider map OpenCode replaces in place. Authswitch lists those instances, offers to stop them, warns when any keep running, and detects the overwrite afterwards — but it cannot prevent it while they run. Restart them after a switch. A running Claude Code picks the switch up instead; its guarantee rests on the behaviour and lock protocol verified against Claude Code 2.1.273, and `authswitch claude active` still reports a login that changed outside authswitch.
986
1052
 
987
1053
  **The Codex stash is keyed by email.** Two Codex workspaces with the same email
988
1054
  cannot both be saved under that key. Their account IDs are distinguished during
@@ -2,7 +2,7 @@
2
2
  * autocreated commitinfo by @push.rocks/commitinfo
3
3
  */
4
4
  export const commitinfo = {
5
- name: "@modelprofile.com/authswitch",
6
- version: "5.2.0",
7
- description: "Manage Codex, OpenCode and Claude Code accounts with guided switching and live usage status"
5
+ name: '@modelprofile.com/authswitch',
6
+ version: '6.1.0',
7
+ description: 'Manage Codex, OpenCode and Claude Code accounts with guided switching and live usage status'
8
8
  }
package/ts/accounts.ts CHANGED
@@ -239,7 +239,8 @@ const STATUS_LOOKUP_CONCURRENCY = 4;
239
239
  * Bounded status lookups: at most four accounts at a time, started in order, each handed the caller's signal.
240
240
  * A lookup that fails reports undefined; once the signal aborts, no further lookup starts. A callback that throws
241
241
  * rejects the call, and no other lookup starts after it. No lookup activates, switches or clears a login, though an
242
- * adapter may renew the tokens of the saved copy it reads (`IAuthHarness.readAccountStatus`).
242
+ * adapter may renew the tokens of the credential it reads, saved or active, on that method's terms
243
+ * (`IAuthHarness.readAccountStatus`).
243
244
  */
244
245
  const lookupStatuses = async (
245
246
  harnessArg: IAuthHarness,
@@ -2,9 +2,9 @@ import * as plugins from './plugins.js';
2
2
  import { FileHarness, type IFileAccount, type IFileHarnessSnapshot } from './classes.fileharness.js';
3
3
  import { CredentialStore, credentialHash, credentialRecord, credentialText, readCredentialDocument, readCredentialRaw, type IStoredCredential } from './classes.credentialstore.js';
4
4
  import { HarnessProcesses } from './classes.harnessprocesses.js';
5
- import { ClaudeAccountStatus } from './classes.claudestatus.js';
5
+ import { ClaudeAccountStatus, type IClaudeLogin } from './classes.claudestatus.js';
6
6
  import { ClaudeCodeLocks } from './classes.claudecodelocks.js';
7
- import { ClaudeTokenRefresh, type IClaudeTokens } from './classes.claudetokenrefresh.js';
7
+ import { claudeGrant, ClaudeTokenRefresh, grantScope, type IClaudeTokens } from './classes.claudetokenrefresh.js';
8
8
  import { CLAUDE_LOGIN_REJECTED, ClaudeLoginRejectedError, ClaudeRateLimitError } from './claudehttp.js';
9
9
  import { writeSecretFileAtomically } from './helpers.js';
10
10
  import type { IHarnessAccountStatus, IHarnessProcessControl, IHarnessState, IHarnessStatusOptions } from './interfaces.harness.js';
@@ -160,8 +160,33 @@ export class ClaudeCodeHarness extends FileHarness {
160
160
  throw new Error('Claude Code switch failed while updating account metadata and was rolled back. The outgoing login remains saved; check authswitch claude doctor.');
161
161
  }
162
162
  }
163
- /** The hash that identifies a saved login's refresh token, so a rejected grant is remembered without keeping it. */
164
- private grantKey(oauthArg: Record<string, unknown>): string { return credentialHash(credentialText(oauthArg.refreshToken) ?? ''); }
163
+ /**
164
+ * The hash that identifies a refused sign-in, so it is remembered without keeping anything of the login.
165
+ *
166
+ * A refusal is about one request: the refresh token it carried, and the client and scopes authswitch derived for
167
+ * it. Binding all three means a login keeps its refusal for as long as authswitch would send the same request
168
+ * again, and that a release which changes the derivation -- adopting a scope set Claude Code changed, say -- gives
169
+ * every such login one honest attempt under the new one instead of repeating a verdict its request no longer earns.
170
+ */
171
+ private grantKey(oauthArg: Record<string, unknown>): string {
172
+ const grant = claudeGrant(oauthArg);
173
+ return credentialHash(JSON.stringify([credentialText(oauthArg.refreshToken) ?? '', grant?.clientId ?? '', grant === null ? '' : grantScope(grant.scopes)]));
174
+ }
175
+
176
+ /** The login a status lookup asks with: its token, and what this store knows about it. */
177
+ private login(accountArg: IFileAccount): IClaudeLogin {
178
+ const oauth = credentialRecord(accountArg.credential.claudeAiOauth);
179
+ const account = credentialRecord(accountArg.credential.oauthAccount);
180
+ const accountUuid = credentialText(account.accountUuid);
181
+ const organizationUuid = credentialText(account.organizationUuid);
182
+ const plan = credentialText(oauth.subscriptionType);
183
+ return {
184
+ accessToken: credentialText(oauth.accessToken) ?? '',
185
+ scopes: Array.isArray(oauth.scopes) ? oauth.scopes.filter((scope): scope is string => typeof scope === 'string') : [],
186
+ ...(accountUuid !== undefined && organizationUuid !== undefined ? { identity: { accountUuid, organizationUuid } } : {}),
187
+ ...(plan === undefined ? {} : { plan }),
188
+ };
189
+ }
165
190
 
166
191
  /**
167
192
  * The harness's accounts, with the saved copy of the active login brought up to date first.
@@ -226,28 +251,28 @@ export class ClaudeCodeHarness extends FileHarness {
226
251
  * is due is refreshed first; when that fails, the status says why and keeps the stored plan, and the saved login is
227
252
  * left exactly as it was.
228
253
  *
229
- * A refresh is only ever sent for a login the native files prove is not the active one (`nativeView`), and a grant
230
- * the service already rejected is not sent again while the saved record still holds it.
254
+ * A refresh is only ever sent for a login the native files prove is not the active one (`nativeView`), and a request
255
+ * the service already refused is not sent again while the saved record would produce the same one (`grantKey`).
231
256
  */
232
257
  public async readAccountStatus(id: string, optionsArg: IHarnessStatusOptions = {}): Promise<IHarnessAccountStatus> {
233
- const read = (accountArg: IFileAccount) =>
234
- this.status.read(credentialRecord(accountArg.credential.claudeAiOauth), credentialRecord(accountArg.credential.oauthAccount), optionsArg);
258
+ const read = (accountArg: IFileAccount) => this.status.read(this.login(accountArg), optionsArg);
235
259
  const view = this.nativeView(id);
236
260
  if (view.active) return read(view.active);
237
261
  const saved = this.savedCredential(id);
262
+ const login = this.login(saved);
238
263
  const oauth = credentialRecord(saved.credential.claudeAiOauth);
239
264
  if (!this.tokens.due(oauth)) return read(saved);
240
265
  if (view.unavailable !== null) {
241
- return this.status.unavailable(oauth, `Login refresh: this saved login's access token has expired and cannot be renewed for this installation. ${view.unavailable}`);
266
+ return this.status.unavailable(login, `Login refresh: this saved login's access token has expired and cannot be renewed for this installation. ${view.unavailable}`);
242
267
  }
243
- if (this.store.read(id).rejectedGrant === this.grantKey(oauth)) return this.status.unavailable(oauth, `Login refresh: ${SAVED_LOGIN_REJECTED}`);
268
+ if (this.store.read(id).rejectedGrant === this.grantKey(oauth)) return this.status.unavailable(login, `Login refresh: ${SAVED_LOGIN_REJECTED}`);
244
269
  let refreshed: IFileAccount;
245
270
  try { refreshed = await this.refreshSaved(id, optionsArg.signal); }
246
271
  catch (error) {
247
272
  if (optionsArg.signal?.aborted) throw error;
248
273
  const problem = error instanceof ClaudeLoginRejectedError ? SAVED_LOGIN_REJECTED
249
274
  : error instanceof Error ? error.message : 'the saved login could not be refreshed.';
250
- return this.status.unavailable(oauth, `Login refresh: ${problem}`,
275
+ return this.status.unavailable(login, `Login refresh: ${problem}`,
251
276
  error instanceof ClaudeRateLimitError ? { retryAt: error.retryAt } : undefined);
252
277
  }
253
278
  return read(refreshed);
@@ -260,7 +285,7 @@ export class ClaudeCodeHarness extends FileHarness {
260
285
  * became active meanwhile belongs to Claude Code and is returned as it is, one in an installation that can no
261
286
  * longer be read is returned unrefreshed, and one another refresh already renewed is not refreshed twice. The new
262
287
  * tokens replace the saved ones only while the record still holds the refresh token that was sent, the
263
- * compare-and-swap Claude Code 2.1.273 applies to its own store (`$fn`, @15410824).
288
+ * compare-and-swap Claude Code 2.1.273 applies to its own store (`$fn`, @191212749).
264
289
  */
265
290
  private refreshSaved(id: string, signal?: AbortSignal): Promise<IFileAccount> {
266
291
  return this.store.locked(async () => {