@lifeaitools/clauth 1.5.25 → 1.5.26
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 +3 -57
- package/package.json +1 -1
package/cli/commands/serve.js
CHANGED
|
@@ -3103,44 +3103,11 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3103
3103
|
}
|
|
3104
3104
|
|
|
3105
3105
|
// ── MCP endpoint auth ──
|
|
3106
|
-
//
|
|
3107
|
-
//
|
|
3106
|
+
// No 401 gate — tunnel URL is the shared secret. Accept all connections.
|
|
3107
|
+
// If Bearer token present, mark as remote for vault scoping.
|
|
3108
3108
|
if (method === "POST" && (reqPath === "/sse" || isMcpPath)) {
|
|
3109
3109
|
const authHeader = req.headers.authorization;
|
|
3110
|
-
|
|
3111
|
-
const isTunnelReq = tunnelUrl && host !== "127.0.0.1" && host !== "localhost" && host !== "::1";
|
|
3112
|
-
const authLogMsg = [
|
|
3113
|
-
`[${new Date().toISOString()}] MCP POST ${reqPath}`,
|
|
3114
|
-
` Host: ${req.headers.host || "(none)"} (tunnel=${isTunnelReq})`,
|
|
3115
|
-
` Authorization: ${authHeader ? (authHeader.startsWith("Bearer ") ? `Bearer ${authHeader.slice(7, 15)}… (known=${oauthTokens.has(authHeader.slice(7))})` : authHeader.slice(0, 30) + "…") : "(none)"}`,
|
|
3116
|
-
` mcp-protocol-version: ${req.headers["mcp-protocol-version"] || "(not set)"}`,
|
|
3117
|
-
` accept: ${req.headers["accept"] || "(not set)"}`,
|
|
3118
|
-
].join("\n") + "\n";
|
|
3119
|
-
try { fs.appendFileSync(LOG_FILE, authLogMsg); } catch {}
|
|
3120
|
-
|
|
3121
|
-
if (isTunnelReq) {
|
|
3122
|
-
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
3123
|
-
const base = oauthBase();
|
|
3124
|
-
const logMsg = `[${new Date().toISOString()}] OAuth: 401 → requiring auth for tunnel POST ${reqPath}\n`;
|
|
3125
|
-
try { fs.appendFileSync(LOG_FILE, logMsg); } catch {}
|
|
3126
|
-
res.writeHead(401, {
|
|
3127
|
-
"Content-Type": "application/json",
|
|
3128
|
-
"WWW-Authenticate": `Bearer resource_metadata="${base}/.well-known/oauth-protected-resource"`,
|
|
3129
|
-
...CORS,
|
|
3130
|
-
});
|
|
3131
|
-
return res.end(JSON.stringify({ error: "unauthorized" }));
|
|
3132
|
-
}
|
|
3133
|
-
const token = authHeader.slice(7);
|
|
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`;
|
|
3138
|
-
try { fs.appendFileSync(LOG_FILE, logMsg); } catch {}
|
|
3139
|
-
res.writeHead(401, { "Content-Type": "application/json", ...CORS });
|
|
3140
|
-
return res.end(JSON.stringify({ error: "invalid_token" }));
|
|
3141
|
-
}
|
|
3142
|
-
req._clauthRemote = true;
|
|
3143
|
-
} else if (authHeader?.startsWith("Bearer ")) {
|
|
3110
|
+
if (authHeader?.startsWith("Bearer ")) {
|
|
3144
3111
|
const token = authHeader.slice(7);
|
|
3145
3112
|
if (oauthTokens.has(token) || token === OAUTH_CLIENT_SECRET) {
|
|
3146
3113
|
req._clauthRemote = true;
|
|
@@ -3207,28 +3174,7 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3207
3174
|
|
|
3208
3175
|
// ── MCP SSE transport — /sse and namespaced paths ────
|
|
3209
3176
|
// GET /sse|/gws|/clauth — open SSE stream, receive endpoint event
|
|
3210
|
-
// Tunnel requests require Bearer token (same as POST above)
|
|
3211
3177
|
if (method === "GET" && (reqPath === "/sse" || isMcpPath)) {
|
|
3212
|
-
const authHeader = req.headers.authorization;
|
|
3213
|
-
const host = (req.headers.host || "").split(":")[0];
|
|
3214
|
-
const isTunnelReq = tunnelUrl && host !== "127.0.0.1" && host !== "localhost" && host !== "::1";
|
|
3215
|
-
if (isTunnelReq) {
|
|
3216
|
-
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
3217
|
-
const base = oauthBase();
|
|
3218
|
-
res.writeHead(401, {
|
|
3219
|
-
"Content-Type": "application/json",
|
|
3220
|
-
"WWW-Authenticate": `Bearer resource_metadata="${base}/.well-known/oauth-protected-resource"`,
|
|
3221
|
-
...CORS,
|
|
3222
|
-
});
|
|
3223
|
-
return res.end(JSON.stringify({ error: "unauthorized" }));
|
|
3224
|
-
}
|
|
3225
|
-
const sseToken = authHeader.slice(7);
|
|
3226
|
-
if (!oauthTokens.has(sseToken) && sseToken !== OAUTH_CLIENT_SECRET) {
|
|
3227
|
-
res.writeHead(401, { "Content-Type": "application/json", ...CORS });
|
|
3228
|
-
return res.end(JSON.stringify({ error: "invalid_token" }));
|
|
3229
|
-
}
|
|
3230
|
-
// Token valid — mark as remote
|
|
3231
|
-
}
|
|
3232
3178
|
const sessionId = `ses_${++sseCounter}_${Date.now()}`;
|
|
3233
3179
|
|
|
3234
3180
|
res.writeHead(200, {
|