@lifeaitools/clauth 1.5.23 → 1.5.25
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 +44 -15
- package/package.json +1 -1
package/cli/commands/serve.js
CHANGED
|
@@ -847,12 +847,12 @@ 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
854
|
<div class="mcp-row">
|
|
855
|
-
<span class="mcp-label">
|
|
855
|
+
<span class="mcp-label">GWS</span>
|
|
856
856
|
<span class="mcp-val" id="mcp-gws-url">—</span>
|
|
857
857
|
<button class="mcp-copy" onclick="copyMcp('mcp-gws-url')">copy</button>
|
|
858
858
|
</div>
|
|
@@ -2330,18 +2330,24 @@ async function wizRunCreateTunnel() {
|
|
|
2330
2330
|
// Step: MCP setup in claude.ai
|
|
2331
2331
|
async function wizShowMcpSetup(hostname) {
|
|
2332
2332
|
wizStep = "mcp_setup";
|
|
2333
|
-
const
|
|
2333
|
+
const clauthUrl = \`https://\${hostname}/clauth\`;
|
|
2334
|
+
const gwsUrl = \`https://\${hostname}/gws\`;
|
|
2334
2335
|
|
|
2335
2336
|
const mcpData = await apiFetch("/mcp-setup");
|
|
2336
2337
|
|
|
2337
2338
|
renderWizBody(\`
|
|
2338
|
-
<div class="wiz-desc">Add
|
|
2339
|
+
<div class="wiz-desc">Add two MCP connectors in claude.ai — one for Clauth, one for GWS:</div>
|
|
2339
2340
|
<div style="display:flex;flex-direction:column;gap:8px;margin-top:10px">
|
|
2340
2341
|
<div class="mcp-row">
|
|
2341
|
-
<span class="mcp-label">URL</span>
|
|
2342
|
-
<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>
|
|
2343
2344
|
<button class="mcp-copy" onclick="wizCopy('wiz-mcp-url',this)">copy</button>
|
|
2344
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>
|
|
2345
2351
|
<div class="mcp-row">
|
|
2346
2352
|
<span class="mcp-label">Client ID</span>
|
|
2347
2353
|
<span class="mcp-val" id="wiz-mcp-cid">\${mcpData?.clientId || '(unlock required)'}</span>
|
|
@@ -2357,7 +2363,7 @@ async function wizShowMcpSetup(hostname) {
|
|
|
2357
2363
|
Paste into <a class="wiz-link" href="https://claude.ai/settings/integrations" target="_blank">claude.ai → Settings → Integrations</a>
|
|
2358
2364
|
</div>
|
|
2359
2365
|
<div style="margin-top:8px;font-size:.78rem;color:#64748b">
|
|
2360
|
-
|
|
2366
|
+
Same Client ID/Secret for both connectors.
|
|
2361
2367
|
</div>
|
|
2362
2368
|
\`, [], [
|
|
2363
2369
|
\`<button class="btn-wiz-primary" onclick="window.open('https://claude.ai/settings/integrations','_blank');wizShowTest()">I've Added It — Test Now</button>\`,
|
|
@@ -2937,7 +2943,7 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
2937
2943
|
if (reqPath.startsWith("/.well-known/oauth-protected-resource")) {
|
|
2938
2944
|
const base = oauthBase();
|
|
2939
2945
|
const suffix = reqPath.replace("/.well-known/oauth-protected-resource", "").replace(/^\//, "");
|
|
2940
|
-
const resourcePath = suffix && ["/gws", "/clauth", "/mcp", "/sse"].includes("/" + suffix) ? "/" + suffix : "/
|
|
2946
|
+
const resourcePath = suffix && ["/gws", "/clauth", "/mcp", "/sse"].includes("/" + suffix) ? "/" + suffix : "/clauth";
|
|
2941
2947
|
res.writeHead(200, { "Content-Type": "application/json", ...CORS });
|
|
2942
2948
|
return res.end(JSON.stringify({
|
|
2943
2949
|
resource: `${base}${resourcePath}`,
|
|
@@ -2956,7 +2962,7 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
2956
2962
|
token_endpoint: `${base}/token`,
|
|
2957
2963
|
registration_endpoint: `${base}/register`,
|
|
2958
2964
|
response_types_supported: ["code"],
|
|
2959
|
-
grant_types_supported: ["authorization_code"],
|
|
2965
|
+
grant_types_supported: ["authorization_code", "client_credentials"],
|
|
2960
2966
|
code_challenge_methods_supported: ["S256"],
|
|
2961
2967
|
scopes_supported: ["mcp:tools"],
|
|
2962
2968
|
}));
|
|
@@ -3032,6 +3038,23 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3032
3038
|
return res.end(JSON.stringify({ error: "invalid_request" }));
|
|
3033
3039
|
}
|
|
3034
3040
|
|
|
3041
|
+
// client_credentials grant — skip authorize/redirect, just issue token from client_id+secret
|
|
3042
|
+
if (body.grant_type === "client_credentials") {
|
|
3043
|
+
const cid = body.client_id;
|
|
3044
|
+
const csec = body.client_secret;
|
|
3045
|
+
if (cid === OAUTH_CLIENT_ID && csec === OAUTH_CLIENT_SECRET) {
|
|
3046
|
+
const accessToken = crypto.randomBytes(32).toString("hex");
|
|
3047
|
+
oauthTokens.add(accessToken);
|
|
3048
|
+
saveTokens(oauthTokens);
|
|
3049
|
+
const logMsg = `[${new Date().toISOString()}] OAuth: client_credentials token issued for ${cid.slice(0,8)}… (token=${accessToken.slice(0,8)}…)\n`;
|
|
3050
|
+
try { fs.appendFileSync(LOG_FILE, logMsg); } catch {}
|
|
3051
|
+
res.writeHead(200, { "Content-Type": "application/json", ...CORS });
|
|
3052
|
+
return res.end(JSON.stringify({ access_token: accessToken, token_type: "Bearer", expires_in: 86400, scope: "mcp:tools" }));
|
|
3053
|
+
}
|
|
3054
|
+
res.writeHead(401, { "Content-Type": "application/json", ...CORS });
|
|
3055
|
+
return res.end(JSON.stringify({ error: "invalid_client" }));
|
|
3056
|
+
}
|
|
3057
|
+
|
|
3035
3058
|
if (body.grant_type !== "authorization_code") {
|
|
3036
3059
|
res.writeHead(400, { "Content-Type": "application/json", ...CORS });
|
|
3037
3060
|
return res.end(JSON.stringify({ error: "unsupported_grant_type" }));
|
|
@@ -3108,15 +3131,20 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3108
3131
|
return res.end(JSON.stringify({ error: "unauthorized" }));
|
|
3109
3132
|
}
|
|
3110
3133
|
const token = authHeader.slice(7);
|
|
3111
|
-
|
|
3112
|
-
|
|
3134
|
+
// Accept: OAuth-issued tokens OR the stable client_secret directly
|
|
3135
|
+
const isValidToken = oauthTokens.has(token) || token === OAUTH_CLIENT_SECRET;
|
|
3136
|
+
if (!isValidToken) {
|
|
3137
|
+
const logMsg = `[${new Date().toISOString()}] OAuth: REJECTED token ${token.slice(0,8)}… (pool=${oauthTokens.size}, secret=${token === OAUTH_CLIENT_SECRET})\n`;
|
|
3113
3138
|
try { fs.appendFileSync(LOG_FILE, logMsg); } catch {}
|
|
3114
3139
|
res.writeHead(401, { "Content-Type": "application/json", ...CORS });
|
|
3115
3140
|
return res.end(JSON.stringify({ error: "invalid_token" }));
|
|
3116
3141
|
}
|
|
3117
3142
|
req._clauthRemote = true;
|
|
3118
|
-
} else if (authHeader?.startsWith("Bearer ")
|
|
3119
|
-
|
|
3143
|
+
} else if (authHeader?.startsWith("Bearer ")) {
|
|
3144
|
+
const token = authHeader.slice(7);
|
|
3145
|
+
if (oauthTokens.has(token) || token === OAUTH_CLIENT_SECRET) {
|
|
3146
|
+
req._clauthRemote = true;
|
|
3147
|
+
}
|
|
3120
3148
|
}
|
|
3121
3149
|
// fall through to MCP handling
|
|
3122
3150
|
}
|
|
@@ -3194,7 +3222,8 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3194
3222
|
});
|
|
3195
3223
|
return res.end(JSON.stringify({ error: "unauthorized" }));
|
|
3196
3224
|
}
|
|
3197
|
-
|
|
3225
|
+
const sseToken = authHeader.slice(7);
|
|
3226
|
+
if (!oauthTokens.has(sseToken) && sseToken !== OAUTH_CLIENT_SECRET) {
|
|
3198
3227
|
res.writeHead(401, { "Content-Type": "application/json", ...CORS });
|
|
3199
3228
|
return res.end(JSON.stringify({ error: "invalid_token" }));
|
|
3200
3229
|
}
|
|
@@ -3365,7 +3394,7 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3365
3394
|
if (method === "GET" && reqPath === "/mcp-setup") {
|
|
3366
3395
|
const base = tunnelUrl && tunnelUrl.startsWith("http") ? tunnelUrl : null;
|
|
3367
3396
|
return ok(res, {
|
|
3368
|
-
url: base ? `${base}/
|
|
3397
|
+
url: base ? `${base}/clauth` : null,
|
|
3369
3398
|
gwsUrl: base ? `${base}/gws` : null,
|
|
3370
3399
|
clientId: OAUTH_CLIENT_ID,
|
|
3371
3400
|
clientSecret: OAUTH_CLIENT_SECRET,
|