@tokenoftrust/cli 1.4.0-rc.2 → 1.4.0-rc.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokenoftrust/cli",
3
- "version": "1.4.0-rc.2",
3
+ "version": "1.4.0-rc.3",
4
4
  "description": "Token of Trust developer CLI — check out a tenant store, run it locally with save→reload, and submit it for preview. Installs the `tot` command.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Token of Trust",
@@ -25,6 +25,7 @@ import { openBrowser } from "../open.mjs";
25
25
  import { fail } from "../errors.mjs";
26
26
  import { cockpitRecoveryUrl, normalizeEmailHint, redactEmailForHint, emailFromJwt } from "../auth.mjs";
27
27
  import { isInteractive, promptYesNo } from "../prompt.mjs";
28
+ import { versionStamp } from "../mcp.mjs";
28
29
 
29
30
  const DEFAULT_MCP_URL = "https://mcp.tokenoftrust.com";
30
31
 
@@ -255,6 +256,10 @@ export async function run(argv, _ctx) {
255
256
  return 0;
256
257
  }
257
258
 
259
+ // Show which CLI/runtime is actually running BEFORE anything else — the first thing
260
+ // a "why did sign-in behave oddly" investigation needs (e.g. a stale shadowing `tot`).
261
+ console.error(versionStamp());
262
+
258
263
  const mcpUrl = args.mcp || env.MCP_BASE_URL || env.TOT_MCP_URL || DEFAULT_MCP_URL;
259
264
 
260
265
  if (args.code) {
package/src/oauth.mjs CHANGED
@@ -84,8 +84,15 @@ export async function registerClient(
84
84
  headers: { "Content-Type": "application/json", Accept: "application/json" },
85
85
  body: JSON.stringify({
86
86
  client_name: CLIENT_NAME,
87
+ // Include the device-code grant: the browserless rendezvous + B3 device flows
88
+ // redeem their device_code at /oauth/token with this grant, so a client
89
+ // registered WITHOUT it gets "unauthorized_client: grant_type is invalid".
90
+ grant_types: [
91
+ "authorization_code",
92
+ "refresh_token",
93
+ "urn:ietf:params:oauth:grant-type:device_code",
94
+ ],
87
95
  redirect_uris: [redirectUri],
88
- grant_types: ["authorization_code", "refresh_token"],
89
96
  response_types: ["code"],
90
97
  token_endpoint_auth_method: "none",
91
98
  scope: SCOPE,
@@ -355,7 +362,6 @@ export async function attachRendezvous(attachEndpoint, { rendezvousCode, clientI
355
362
  */
356
363
  export async function rendezvousLoginFlow({
357
364
  mcpUrl,
358
- clientId,
359
365
  code,
360
366
  fetchImpl = fetch,
361
367
  log = () => {},
@@ -363,7 +369,12 @@ export async function rendezvousLoginFlow({
363
369
  now = () => Date.now(),
364
370
  }) {
365
371
  const meta = await discoverMetadata(mcpUrl, fetchImpl);
366
- const resolvedClientId = clientId || (await registerClient(meta.registration_endpoint, LOOPBACK_REDIRECT, fetchImpl));
372
+ // Always register a FRESH client for a rendezvous sign-in — do NOT reuse a cached
373
+ // clientId. A client cached by an older CLI build was registered without the
374
+ // device-code grant, so /oauth/token would reject the device grant with
375
+ // "unauthorized_client". Registration is cheap and a rendezvous has no consent
376
+ // screen to re-trigger (unlike the loopback/device flows, which reuse the cache).
377
+ const resolvedClientId = await registerClient(meta.registration_endpoint, LOOPBACK_REDIRECT, fetchImpl);
367
378
  const { verifier, challenge } = generatePkce();
368
379
 
369
380
  const attach = await attachRendezvous(