@lifeaitools/clauth 1.5.26 → 1.5.28
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 +13 -55
- package/package.json +1 -1
package/cli/commands/serve.js
CHANGED
|
@@ -2934,38 +2934,14 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
2934
2934
|
return res.end();
|
|
2935
2935
|
}
|
|
2936
2936
|
|
|
2937
|
-
// ── OAuth Discovery
|
|
2938
|
-
// claude.ai
|
|
2939
|
-
//
|
|
2940
|
-
//
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
const suffix = reqPath.replace("/.well-known/oauth-protected-resource", "").replace(/^\//, "");
|
|
2946
|
-
const resourcePath = suffix && ["/gws", "/clauth", "/mcp", "/sse"].includes("/" + suffix) ? "/" + suffix : "/clauth";
|
|
2947
|
-
res.writeHead(200, { "Content-Type": "application/json", ...CORS });
|
|
2948
|
-
return res.end(JSON.stringify({
|
|
2949
|
-
resource: `${base}${resourcePath}`,
|
|
2950
|
-
authorization_servers: [base],
|
|
2951
|
-
scopes_supported: ["mcp:tools"],
|
|
2952
|
-
bearer_methods_supported: ["header"],
|
|
2953
|
-
}));
|
|
2954
|
-
}
|
|
2955
|
-
|
|
2956
|
-
if (reqPath === "/.well-known/oauth-authorization-server") {
|
|
2957
|
-
const base = oauthBase();
|
|
2958
|
-
res.writeHead(200, { "Content-Type": "application/json", ...CORS });
|
|
2959
|
-
return res.end(JSON.stringify({
|
|
2960
|
-
issuer: base,
|
|
2961
|
-
authorization_endpoint: `${base}/authorize`,
|
|
2962
|
-
token_endpoint: `${base}/token`,
|
|
2963
|
-
registration_endpoint: `${base}/register`,
|
|
2964
|
-
response_types_supported: ["code"],
|
|
2965
|
-
grant_types_supported: ["authorization_code", "client_credentials"],
|
|
2966
|
-
code_challenge_methods_supported: ["S256"],
|
|
2967
|
-
scopes_supported: ["mcp:tools"],
|
|
2968
|
-
}));
|
|
2937
|
+
// ── OAuth Discovery — 404 well-known only ──────────────
|
|
2938
|
+
// claude.ai ignores metadata endpoints and constructs /register, /authorize,
|
|
2939
|
+
// /token from the domain root (issue #82). Keep well-known as 404 so claude.ai
|
|
2940
|
+
// uses the fallback paths. OAuth endpoints below are live.
|
|
2941
|
+
if (reqPath.startsWith("/.well-known/oauth-protected-resource") ||
|
|
2942
|
+
reqPath === "/.well-known/oauth-authorization-server") {
|
|
2943
|
+
res.writeHead(404, { "Content-Type": "application/json", ...CORS });
|
|
2944
|
+
return res.end(JSON.stringify({ error: "not_found" }));
|
|
2969
2945
|
}
|
|
2970
2946
|
|
|
2971
2947
|
// ── Dynamic Client Registration (RFC 7591) ──────────────
|
|
@@ -2998,7 +2974,6 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
2998
2974
|
const redirectUri = url.searchParams.get("redirect_uri");
|
|
2999
2975
|
const state = url.searchParams.get("state");
|
|
3000
2976
|
const codeChallenge = url.searchParams.get("code_challenge");
|
|
3001
|
-
const codeChallengeMethod = url.searchParams.get("code_challenge_method");
|
|
3002
2977
|
|
|
3003
2978
|
if (!clientId || !redirectUri) {
|
|
3004
2979
|
res.writeHead(400, { "Content-Type": "text/plain", ...CORS });
|
|
@@ -3008,7 +2983,7 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3008
2983
|
const code = crypto.randomBytes(32).toString("hex");
|
|
3009
2984
|
oauthCodes.set(code, {
|
|
3010
2985
|
client_id: clientId, redirect_uri: redirectUri,
|
|
3011
|
-
code_challenge: codeChallenge,
|
|
2986
|
+
code_challenge: codeChallenge,
|
|
3012
2987
|
expires: Date.now() + 300_000,
|
|
3013
2988
|
});
|
|
3014
2989
|
|
|
@@ -3016,7 +2991,7 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3016
2991
|
redirect.searchParams.set("code", code);
|
|
3017
2992
|
if (state) redirect.searchParams.set("state", state);
|
|
3018
2993
|
|
|
3019
|
-
const logMsg = `[${new Date().toISOString()}] OAuth: authorize → code
|
|
2994
|
+
const logMsg = `[${new Date().toISOString()}] OAuth: authorize → code for ${clientId}, redirect to ${redirect.origin}\n`;
|
|
3020
2995
|
try { fs.appendFileSync(LOG_FILE, logMsg); } catch {}
|
|
3021
2996
|
res.writeHead(302, { Location: redirect.toString(), ...CORS });
|
|
3022
2997
|
return res.end();
|
|
@@ -3038,23 +3013,6 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3038
3013
|
return res.end(JSON.stringify({ error: "invalid_request" }));
|
|
3039
3014
|
}
|
|
3040
3015
|
|
|
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
|
-
|
|
3058
3016
|
if (body.grant_type !== "authorization_code") {
|
|
3059
3017
|
res.writeHead(400, { "Content-Type": "application/json", ...CORS });
|
|
3060
3018
|
return res.end(JSON.stringify({ error: "unsupported_grant_type" }));
|
|
@@ -3073,7 +3031,7 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3073
3031
|
if (computed !== stored.code_challenge) {
|
|
3074
3032
|
oauthCodes.delete(body.code);
|
|
3075
3033
|
res.writeHead(400, { "Content-Type": "application/json", ...CORS });
|
|
3076
|
-
return res.end(JSON.stringify({ error: "invalid_grant", error_description: "PKCE
|
|
3034
|
+
return res.end(JSON.stringify({ error: "invalid_grant", error_description: "PKCE failed" }));
|
|
3077
3035
|
}
|
|
3078
3036
|
}
|
|
3079
3037
|
|
|
@@ -3082,10 +3040,10 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3082
3040
|
oauthTokens.add(accessToken);
|
|
3083
3041
|
saveTokens(oauthTokens);
|
|
3084
3042
|
|
|
3085
|
-
const logMsg = `[${new Date().toISOString()}] OAuth: token issued for
|
|
3043
|
+
const logMsg = `[${new Date().toISOString()}] OAuth: token issued for ${stored.client_id} (token=${accessToken.slice(0,8)}…)\n`;
|
|
3086
3044
|
try { fs.appendFileSync(LOG_FILE, logMsg); } catch {}
|
|
3087
3045
|
res.writeHead(200, { "Content-Type": "application/json", ...CORS });
|
|
3088
|
-
return res.end(JSON.stringify({ access_token: accessToken, token_type: "Bearer", expires_in: 86400 }));
|
|
3046
|
+
return res.end(JSON.stringify({ access_token: accessToken, token_type: "Bearer", scope: "mcp:tools", expires_in: 86400 }));
|
|
3089
3047
|
}
|
|
3090
3048
|
|
|
3091
3049
|
// ── MCP path helpers ──
|