@lifeaitools/clauth 1.5.22 → 1.5.24

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.
@@ -847,10 +847,15 @@ function dashboardHtml(port, whitelist, isStaged = false) {
847
847
  <div class="mcp-setup-title">claude.ai MCP Integration</div>
848
848
  <div class="oauth-fields">
849
849
  <div class="mcp-row">
850
- <span class="mcp-label">URL</span>
850
+ <span class="mcp-label">Clauth</span>
851
851
  <span class="mcp-val" id="mcp-url">—</span>
852
852
  <button class="mcp-copy" onclick="copyMcp('mcp-url')">copy</button>
853
853
  </div>
854
+ <div class="mcp-row">
855
+ <span class="mcp-label">GWS</span>
856
+ <span class="mcp-val" id="mcp-gws-url">—</span>
857
+ <button class="mcp-copy" onclick="copyMcp('mcp-gws-url')">copy</button>
858
+ </div>
854
859
  <div class="mcp-row">
855
860
  <span class="mcp-label">Client ID</span>
856
861
  <span class="mcp-val" id="mcp-client-id">—</span>
@@ -862,7 +867,10 @@ function dashboardHtml(port, whitelist, isStaged = false) {
862
867
  <button class="mcp-copy" onclick="copyMcp('mcp-client-secret')">copy</button>
863
868
  </div>
864
869
  </div>
865
- <div style="font-size:.72rem;color:#64748b;margin-top:4px">Paste these into <a href="https://claude.ai/settings/integrations" target="_blank" style="color:#60a5fa">claude.ai Settings → Integrations</a></div>
870
+ <div style="display:flex;align-items:center;gap:8px;margin-top:6px">
871
+ <div style="font-size:.72rem;color:#64748b">Paste into <a href="https://claude.ai/settings/integrations" target="_blank" style="color:#60a5fa">claude.ai → Integrations</a></div>
872
+ <button class="mcp-copy" onclick="rollMcpCreds()" style="font-size:.7rem">Roll Credentials</button>
873
+ </div>
866
874
  </div>
867
875
 
868
876
  <div class="wizard-panel" id="wizard-panel">
@@ -1939,10 +1947,12 @@ async function toggleMcpSetup() {
1939
1947
  try {
1940
1948
  const m = await fetch(BASE + "/mcp-setup").then(r => r.json());
1941
1949
  document.getElementById("mcp-url").textContent = m.url || "(tunnel not running)";
1950
+ document.getElementById("mcp-gws-url").textContent = m.gwsUrl || "(tunnel not running)";
1942
1951
  document.getElementById("mcp-client-id").textContent = m.clientId || "—";
1943
1952
  document.getElementById("mcp-client-secret").textContent = m.clientSecret || "—";
1944
1953
  } catch {
1945
1954
  document.getElementById("mcp-url").textContent = "(error fetching)";
1955
+ document.getElementById("mcp-gws-url").textContent = "(error fetching)";
1946
1956
  }
1947
1957
  }
1948
1958
  }
@@ -1958,6 +1968,17 @@ function copyMcp(elId) {
1958
1968
  }).catch(() => {});
1959
1969
  }
1960
1970
 
1971
+ async function rollMcpCreds() {
1972
+ if (!confirm("Roll MCP credentials? You will need to re-add connectors in claude.ai with the new credentials.")) return;
1973
+ try {
1974
+ const resp = await fetch(BASE + "/roll-mcp-creds", { method: "POST" }).then(r => r.json());
1975
+ if (resp.client_id) {
1976
+ document.getElementById("mcp-client-id").textContent = resp.client_id;
1977
+ document.getElementById("mcp-client-secret").textContent = resp.client_secret;
1978
+ }
1979
+ } catch(e) { alert("Failed: " + e.message); }
1980
+ }
1981
+
1961
1982
  // ── Tunnel Setup Wizard ─────────────────────
1962
1983
  let wizStep = null;
1963
1984
  let wizData = {};
@@ -2309,18 +2330,24 @@ async function wizRunCreateTunnel() {
2309
2330
  // Step: MCP setup in claude.ai
2310
2331
  async function wizShowMcpSetup(hostname) {
2311
2332
  wizStep = "mcp_setup";
2312
- const sseUrl = \`https://\${hostname}/sse\`;
2333
+ const clauthUrl = \`https://\${hostname}/clauth\`;
2334
+ const gwsUrl = \`https://\${hostname}/gws\`;
2313
2335
 
2314
2336
  const mcpData = await apiFetch("/mcp-setup");
2315
2337
 
2316
2338
  renderWizBody(\`
2317
- <div class="wiz-desc">Add clauth as an MCP server in claude.ai settings. Paste these values:</div>
2339
+ <div class="wiz-desc">Add two MCP connectors in claude.ai one for Clauth, one for GWS:</div>
2318
2340
  <div style="display:flex;flex-direction:column;gap:8px;margin-top:10px">
2319
2341
  <div class="mcp-row">
2320
- <span class="mcp-label">URL</span>
2321
- <span class="mcp-val" id="wiz-mcp-url">\${sseUrl}</span>
2342
+ <span class="mcp-label">Clauth URL</span>
2343
+ <span class="mcp-val" id="wiz-mcp-url">\${clauthUrl}</span>
2322
2344
  <button class="mcp-copy" onclick="wizCopy('wiz-mcp-url',this)">copy</button>
2323
2345
  </div>
2346
+ <div class="mcp-row">
2347
+ <span class="mcp-label">GWS URL</span>
2348
+ <span class="mcp-val" id="wiz-mcp-gws">\${gwsUrl}</span>
2349
+ <button class="mcp-copy" onclick="wizCopy('wiz-mcp-gws',this)">copy</button>
2350
+ </div>
2324
2351
  <div class="mcp-row">
2325
2352
  <span class="mcp-label">Client ID</span>
2326
2353
  <span class="mcp-val" id="wiz-mcp-cid">\${mcpData?.clientId || '(unlock required)'}</span>
@@ -2335,13 +2362,28 @@ async function wizShowMcpSetup(hostname) {
2335
2362
  <div style="margin-top:10px;font-size:.78rem;color:#64748b">
2336
2363
  Paste into <a class="wiz-link" href="https://claude.ai/settings/integrations" target="_blank">claude.ai → Settings → Integrations</a>
2337
2364
  </div>
2365
+ <div style="margin-top:8px;font-size:.78rem;color:#64748b">
2366
+ Same Client ID/Secret for both connectors.
2367
+ </div>
2338
2368
  \`, [], [
2339
2369
  \`<button class="btn-wiz-primary" onclick="window.open('https://claude.ai/settings/integrations','_blank');wizShowTest()">I've Added It — Test Now</button>\`,
2370
+ \`<button class="btn-wiz-secondary" onclick="wizRollCreds()">Roll Credentials</button>\`,
2340
2371
  \`<button class="btn-wiz-secondary" onclick="wizShowTest()">Skip Test</button>\`,
2341
2372
  \`<button class="btn-wiz-secondary" onclick="closeSetupWizard()">Done</button>\`
2342
2373
  ]);
2343
2374
  }
2344
2375
 
2376
+ async function wizRollCreds() {
2377
+ if (!confirm("Roll MCP credentials? Existing claude.ai connectors will need to be re-added with the new credentials.")) return;
2378
+ try {
2379
+ const resp = await apiFetch("/roll-mcp-creds", { method: "POST" });
2380
+ if (resp?.client_id) {
2381
+ document.getElementById("wiz-mcp-cid").textContent = resp.client_id;
2382
+ document.getElementById("wiz-mcp-sec").textContent = resp.client_secret;
2383
+ }
2384
+ } catch(e) { alert("Failed to roll credentials: " + e.message); }
2385
+ }
2386
+
2345
2387
  function wizCopy(elId, btn) {
2346
2388
  const val = document.getElementById(elId)?.textContent?.trim();
2347
2389
  if (!val) return;
@@ -2531,8 +2573,8 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
2531
2573
  return creds;
2532
2574
  }
2533
2575
  const stableCreds = loadOrCreateCreds();
2534
- const OAUTH_CLIENT_ID = stableCreds.client_id;
2535
- const OAUTH_CLIENT_SECRET = stableCreds.client_secret;
2576
+ let OAUTH_CLIENT_ID = stableCreds.client_id;
2577
+ let OAUTH_CLIENT_SECRET = stableCreds.client_secret;
2536
2578
  oauthClients.set(OAUTH_CLIENT_ID, {
2537
2579
  client_id: OAUTH_CLIENT_ID, client_secret: OAUTH_CLIENT_SECRET,
2538
2580
  client_name: "claude.ai", redirect_uris: ["https://claude.ai/api/mcp/auth_callback"],
@@ -2901,7 +2943,7 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
2901
2943
  if (reqPath.startsWith("/.well-known/oauth-protected-resource")) {
2902
2944
  const base = oauthBase();
2903
2945
  const suffix = reqPath.replace("/.well-known/oauth-protected-resource", "").replace(/^\//, "");
2904
- const resourcePath = suffix && ["/gws", "/clauth", "/mcp", "/sse"].includes("/" + suffix) ? "/" + suffix : "/sse";
2946
+ const resourcePath = suffix && ["/gws", "/clauth", "/mcp", "/sse"].includes("/" + suffix) ? "/" + suffix : "/clauth";
2905
2947
  res.writeHead(200, { "Content-Type": "application/json", ...CORS });
2906
2948
  return res.end(JSON.stringify({
2907
2949
  resource: `${base}${resourcePath}`,
@@ -3327,13 +3369,42 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
3327
3369
 
3328
3370
  // GET /mcp-setup — OAuth credentials for claude.ai MCP setup (localhost only)
3329
3371
  if (method === "GET" && reqPath === "/mcp-setup") {
3372
+ const base = tunnelUrl && tunnelUrl.startsWith("http") ? tunnelUrl : null;
3330
3373
  return ok(res, {
3331
- url: tunnelUrl && tunnelUrl.startsWith("http") ? `${tunnelUrl}/mcp` : null,
3374
+ url: base ? `${base}/clauth` : null,
3375
+ gwsUrl: base ? `${base}/gws` : null,
3332
3376
  clientId: OAUTH_CLIENT_ID,
3333
3377
  clientSecret: OAUTH_CLIENT_SECRET,
3334
3378
  });
3335
3379
  }
3336
3380
 
3381
+ // POST /roll-mcp-creds — generate new client ID/secret, invalidate all tokens
3382
+ if (method === "POST" && reqPath === "/roll-mcp-creds") {
3383
+ if (lockedGuard(res)) return;
3384
+ const newId = crypto.randomBytes(16).toString("hex");
3385
+ const newSecret = crypto.randomBytes(32).toString("hex");
3386
+ // Update in-memory
3387
+ oauthClients.delete(OAUTH_CLIENT_ID);
3388
+ OAUTH_CLIENT_ID = newId;
3389
+ OAUTH_CLIENT_SECRET = newSecret;
3390
+ stableCreds.client_id = newId;
3391
+ stableCreds.client_secret = newSecret;
3392
+ try { fs.writeFileSync(CREDS_FILE, JSON.stringify(stableCreds)); } catch {}
3393
+ // Register new client
3394
+ oauthClients.set(newId, {
3395
+ client_id: newId, client_secret: newSecret,
3396
+ client_name: "claude.ai", redirect_uris: ["https://claude.ai/api/mcp/auth_callback"],
3397
+ grant_types: ["authorization_code"], response_types: ["code"],
3398
+ token_endpoint_auth_method: "client_secret_post",
3399
+ });
3400
+ // Invalidate all existing tokens
3401
+ oauthTokens.clear();
3402
+ saveTokens(oauthTokens);
3403
+ const logMsg = `[${new Date().toISOString()}] OAuth: rolled credentials — new client ${newId.slice(0,8)}…, all tokens invalidated\n`;
3404
+ try { fs.appendFileSync(LOG_FILE, logMsg); } catch {}
3405
+ return ok(res, { client_id: newId, client_secret: newSecret, tokens_invalidated: true });
3406
+ }
3407
+
3337
3408
  // POST /tunnel — start or stop tunnel manually (action in body)
3338
3409
  if (method === "POST" && reqPath === "/tunnel") {
3339
3410
  if (lockedGuard(res)) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifeaitools/clauth",
3
- "version": "1.5.22",
3
+ "version": "1.5.24",
4
4
  "description": "Hardware-bound credential vault for the LIFEAI infrastructure stack",
5
5
  "type": "module",
6
6
  "bin": {