@lifeaitools/clauth 1.5.63 → 1.5.65

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.
@@ -2560,18 +2560,27 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
2560
2560
  let tunnelStatus = "not_started"; // "not_started" | "not_configured" | "starting" | "live" | "error" | "missing_cloudflared"
2561
2561
 
2562
2562
  // ── OAuth provider (self-contained for claude.ai MCP) ──────
2563
- const oauthClients = new Map(); // client_id → { redirect_uris, client_name, token_endpoint_auth_method }
2564
2563
  const oauthCodes = new Map(); // code → { client_id, redirect_uri, code_challenge, expires }
2565
2564
 
2566
- // Persist tokens + credentials to disk so daemon restarts don't invalidate sessions
2567
- const TOKENS_FILE = path.join(os.tmpdir(), "clauth-oauth-tokens.json");
2565
+ // Persist tokens + clients to disk so daemon restarts don't invalidate sessions
2566
+ const TOKENS_FILE = path.join(os.tmpdir(), "clauth-oauth-tokens.json");
2567
+ const CLIENTS_FILE = path.join(os.tmpdir(), "clauth-oauth-clients.json");
2568
+
2568
2569
  function loadTokens() {
2569
2570
  try { return new Set(JSON.parse(fs.readFileSync(TOKENS_FILE, "utf8"))); } catch { return new Set(); }
2570
2571
  }
2571
2572
  function saveTokens(set) {
2572
2573
  try { fs.writeFileSync(TOKENS_FILE, JSON.stringify([...set])); } catch {}
2573
2574
  }
2574
- const oauthTokens = loadTokens(); // active access tokens — persisted across restarts
2575
+ function loadClients() {
2576
+ try { return new Map(JSON.parse(fs.readFileSync(CLIENTS_FILE, "utf8"))); } catch { return new Map(); }
2577
+ }
2578
+ function saveClients(map) {
2579
+ try { fs.writeFileSync(CLIENTS_FILE, JSON.stringify([...map])); } catch {}
2580
+ }
2581
+
2582
+ const oauthTokens = loadTokens(); // active access tokens — persisted across restarts
2583
+ const oauthClients = loadClients(); // registered OAuth clients — persisted across restarts
2575
2584
 
2576
2585
  function oauthBase() { return tunnelUrl || `http://127.0.0.1:${port}`; }
2577
2586
  function sha256base64url(str) { return crypto.createHash("sha256").update(str).digest("base64url"); }
@@ -2993,6 +3002,7 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
2993
3002
  token_endpoint_auth_method: "none", // PUBLIC CLIENT
2994
3003
  };
2995
3004
  oauthClients.set(clientId, client);
3005
+ saveClients(oauthClients);
2996
3006
  const logMsg = `[${new Date().toISOString()}] OAuth: registered public client ${clientId} (${client.client_name})\n`;
2997
3007
  try { fs.appendFileSync(LOG_FILE, logMsg); } catch {}
2998
3008
  res.writeHead(201, { "Content-Type": "application/json", "Cache-Control": "no-store", ...CORS });
@@ -3242,6 +3252,12 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
3242
3252
 
3243
3253
  // ── MCP SSE transport — /sse and namespaced paths ────
3244
3254
  // GET /sse|/gws|/clauth — open SSE stream, receive endpoint event
3255
+ // Remote clients (claude.ai) use Streamable HTTP (POST only) — return 404 on GET
3256
+ // so claude.ai knows to POST directly rather than trying SSE transport.
3257
+ if (method === "GET" && isMcpPath && req._clauthRemote) {
3258
+ res.writeHead(404, { "Content-Type": "application/json", ...CORS });
3259
+ return res.end(JSON.stringify({ error: "Use POST for Streamable HTTP transport" }));
3260
+ }
3245
3261
  if (method === "GET" && (reqPath === "/sse" || isMcpPath)) {
3246
3262
  const sessionId = `ses_${++sseCounter}_${Date.now()}`;
3247
3263
 
@@ -3578,6 +3594,7 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
3578
3594
  if (lockedGuard(res)) return;
3579
3595
  // Clear all dynamic clients and tokens
3580
3596
  oauthClients.clear();
3597
+ saveClients(oauthClients);
3581
3598
  oauthTokens.clear();
3582
3599
  saveTokens(oauthTokens);
3583
3600
  const logMsg = `[${new Date().toISOString()}] OAuth: rolled credentials — all clients and tokens invalidated\n`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifeaitools/clauth",
3
- "version": "1.5.63",
3
+ "version": "1.5.65",
4
4
  "description": "Hardware-bound credential vault for the LIFEAI infrastructure stack",
5
5
  "type": "module",
6
6
  "bin": {