@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.
- package/cli/commands/serve.js +81 -10
- package/package.json +1 -1
package/cli/commands/serve.js
CHANGED
|
@@ -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">
|
|
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="
|
|
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
|
|
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
|
|
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">\${
|
|
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
|
-
|
|
2535
|
-
|
|
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 : "/
|
|
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:
|
|
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;
|