@michael-joseph-miller/ant-bot 0.3.0 → 0.3.1

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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,19 @@ All notable changes to ant-bot are recorded here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and versions follow
5
5
  [semantic versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.3.1] — 2026-08-24
8
+
9
+ ### Fixed
10
+
11
+ - **Sign-in accepts a client secret.** Google's "Web application" OAuth clients authenticate at
12
+ the token endpoint, so a client ID alone got as far as the consent screen and then failed with
13
+ the provider's own `client_secret is missing`. Both the CLI (`--client-secret`) and the
14
+ Connectors screen now take one, and ant-bot explains what is needed rather than passing that
15
+ message through unhelpfully.
16
+ - **Client credentials are remembered.** They are registered once with a provider and outlive any
17
+ token, so they are stored in the keychain under their own key — a second sign-in, after an
18
+ expiry or a failed exchange, needs no flags.
19
+
7
20
  ## [0.3.0] — 2026-08-24
8
21
 
9
22
  ### Added
package/README.md CHANGED
@@ -280,10 +280,10 @@ Current totals, as run against this checkout:
280
280
  | Package | Test files | Tests |
281
281
  |---|---|---|
282
282
  | `@antbot/contract` | 1 | 34 |
283
- | `@antbot/daemon` | 25 | 573 |
284
- | `@antbot/ui` | 9 | 90 |
283
+ | `@antbot/daemon` | 25 | 575 |
284
+ | `@antbot/ui` | 9 | 92 |
285
285
  | `@antbot/cli` | 8 | 140 |
286
- | **Total** | **43** | **837** |
286
+ | **Total** | **43** | **841** |
287
287
 
288
288
  ## Status / not built
289
289
 
package/dist/server.js CHANGED
@@ -2306,6 +2306,7 @@ async function refreshTokens(tokens, now2 = Date.now()) {
2306
2306
  // daemon/src/connectors/auth.ts
2307
2307
  var log7 = logger("connector-auth");
2308
2308
  var tokenSecretName = (connectorName) => `antbot:oauth:${connectorName}`;
2309
+ var clientSecretName = (connectorName) => `antbot:oauth-client:${connectorName}`;
2309
2310
  var redirectUri = (port) => `http://127.0.0.1:${port}/api/connectors/oauth/callback`;
2310
2311
  var LOGIN_TTL_MS = 10 * 60 * 1e3;
2311
2312
  var ConnectorAuthService = class {
@@ -2337,6 +2338,20 @@ var ConnectorAuthService = class {
2337
2338
  async signOut(connectorName) {
2338
2339
  await this.secrets.remove(tokenSecretName(connectorName));
2339
2340
  }
2341
+ /** Forget the tokens *and* the registered client. Used when the credentials themselves are wrong. */
2342
+ async forgetClient(connectorName) {
2343
+ await this.secrets.remove(clientSecretName(connectorName));
2344
+ }
2345
+ async readClient(connectorName) {
2346
+ const key = clientSecretName(connectorName);
2347
+ const found = (await this.secrets.resolve([key])).get(key);
2348
+ if (!found) return null;
2349
+ try {
2350
+ return JSON.parse(found);
2351
+ } catch {
2352
+ return null;
2353
+ }
2354
+ }
2340
2355
  /**
2341
2356
  * Begin a sign-in. Returns the URL the human must open.
2342
2357
  *
@@ -2350,8 +2365,9 @@ var ConnectorAuthService = class {
2350
2365
  }
2351
2366
  const discovery = await discoverAuth(connector.config.url);
2352
2367
  const redirect = redirectUri(this.port);
2353
- let clientId = opts.clientId;
2354
- let clientSecret = opts.clientSecret;
2368
+ const remembered = await this.readClient(connector.name);
2369
+ let clientId = opts.clientId ?? remembered?.clientId;
2370
+ let clientSecret = opts.clientSecret ?? (opts.clientId ? void 0 : remembered?.clientSecret);
2355
2371
  if (!clientId && discovery.authServer.registrationEndpoint) {
2356
2372
  const registered = await registerClient(discovery.authServer.registrationEndpoint, redirect);
2357
2373
  clientId = registered?.clientId;
@@ -2362,6 +2378,9 @@ var ConnectorAuthService = class {
2362
2378
  `${new URL(discovery.authServer.authorizationEndpoint).host} does not support automatic app registration, so it needs a client ID you create yourself. Register one with that provider, add "${redirect}" as an authorised redirect URI, and pass the client ID with --client-id.`
2363
2379
  );
2364
2380
  }
2381
+ if (opts.clientId || opts.clientSecret || !remembered) {
2382
+ await this.secrets.set(clientSecretName(connector.name), JSON.stringify({ clientId, clientSecret }));
2383
+ }
2365
2384
  const pkce = createPkce();
2366
2385
  const state = crypto2.randomBytes(16).toString("base64url");
2367
2386
  this.pending.set(state, {
@@ -2394,15 +2413,26 @@ var ConnectorAuthService = class {
2394
2413
  const p = this.pending.get(state);
2395
2414
  if (!p) throw new OAuthError("This sign-in link is no longer valid. Start the sign-in again.");
2396
2415
  this.pending.delete(state);
2397
- const tokens = await exchangeCode({
2398
- tokenEndpoint: p.tokenEndpoint,
2399
- code,
2400
- verifier: p.verifier,
2401
- clientId: p.clientId,
2402
- clientSecret: p.clientSecret,
2403
- redirectUri: p.redirectUri,
2404
- resource: p.resource
2405
- });
2416
+ let tokens;
2417
+ try {
2418
+ tokens = await exchangeCode({
2419
+ tokenEndpoint: p.tokenEndpoint,
2420
+ code,
2421
+ verifier: p.verifier,
2422
+ clientId: p.clientId,
2423
+ clientSecret: p.clientSecret,
2424
+ redirectUri: p.redirectUri,
2425
+ resource: p.resource
2426
+ });
2427
+ } catch (err) {
2428
+ const message = err.message;
2429
+ if (/client_secret/i.test(message)) {
2430
+ throw new OAuthError(
2431
+ `This provider requires a client secret as well as a client ID. Add the secret from the same OAuth client (in Google's console: the client's "Client secret") and sign in again.`
2432
+ );
2433
+ }
2434
+ throw err;
2435
+ }
2406
2436
  await this.write(p.connectorName, tokens);
2407
2437
  log7.info(`connector "${p.connectorName}" signed in`);
2408
2438
  return { connectorId: p.connectorId, connectorName: p.connectorName };