@lifeaitools/clauth 1.5.16 → 1.5.18

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.
Files changed (2) hide show
  1. package/cli/commands/serve.js +11 -135
  2. package/package.json +1 -1
@@ -2878,143 +2878,19 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
2878
2878
  return res.end();
2879
2879
  }
2880
2880
 
2881
- // ── OAuth Discovery (RFC 9728 + RFC 8414) ──────────────
2882
- if (reqPath.startsWith("/.well-known/oauth-protected-resource")) {
2883
- // Only advertise OAuth for /mcp — /gws and /clauth are open (no OAuth).
2884
- // Advertising OAuth on open paths causes claude.ai to do an OAuth dance,
2885
- // get a token, then have no retry context (since the original 200 wasn't a 401).
2886
- const suffix = reqPath.replace("/.well-known/oauth-protected-resource", "").replace(/^\//, "") || "mcp";
2887
- if (suffix !== "mcp" && suffix !== "") {
2888
- // Path-specific OAuth metadata requested for a non-mcp path — 404 it
2889
- res.writeHead(404, { "Content-Type": "application/json", ...CORS });
2890
- return res.end(JSON.stringify({ error: "not_found" }));
2891
- }
2892
- const base = oauthBase();
2893
- res.writeHead(200, { "Content-Type": "application/json", ...CORS });
2894
- return res.end(JSON.stringify({
2895
- resource: `${base}/mcp`,
2896
- authorization_servers: [base],
2897
- scopes_supported: ["mcp:tools"],
2898
- bearer_methods_supported: ["header"],
2899
- }));
2900
- }
2901
-
2902
- if (reqPath === "/.well-known/oauth-authorization-server") {
2903
- const base = oauthBase();
2904
- res.writeHead(200, { "Content-Type": "application/json", ...CORS });
2905
- return res.end(JSON.stringify({
2906
- issuer: base,
2907
- authorization_endpoint: `${base}/authorize`,
2908
- token_endpoint: `${base}/token`,
2909
- registration_endpoint: `${base}/register`,
2910
- response_types_supported: ["code"],
2911
- grant_types_supported: ["authorization_code"],
2912
- code_challenge_methods_supported: ["S256"],
2913
- scopes_supported: ["mcp:tools"],
2914
- }));
2915
- }
2916
-
2917
- // ── Dynamic Client Registration (RFC 7591) ──────────────
2918
- if (method === "POST" && reqPath === "/register") {
2919
- let body;
2920
- try { body = await readBody(req); } catch {
2921
- res.writeHead(400, { "Content-Type": "application/json", ...CORS });
2922
- return res.end(JSON.stringify({ error: "invalid_request" }));
2923
- }
2924
- const clientId = crypto.randomBytes(16).toString("hex");
2925
- const clientSecret = crypto.randomBytes(32).toString("hex");
2926
- const client = {
2927
- client_id: clientId, client_secret: clientSecret,
2928
- client_name: body.client_name || "unknown",
2929
- redirect_uris: body.redirect_uris || [],
2930
- grant_types: body.grant_types || ["authorization_code"],
2931
- response_types: body.response_types || ["code"],
2932
- token_endpoint_auth_method: body.token_endpoint_auth_method || "client_secret_post",
2933
- };
2934
- oauthClients.set(clientId, client);
2935
- const logMsg = `[${new Date().toISOString()}] OAuth: registered client ${clientId} (${client.client_name})\n`;
2936
- try { fs.appendFileSync(LOG_FILE, logMsg); } catch {}
2937
- res.writeHead(201, { "Content-Type": "application/json", ...CORS });
2938
- return res.end(JSON.stringify(client));
2939
- }
2940
-
2941
- // ── Authorization endpoint — auto-approve ──────────────
2942
- if (method === "GET" && reqPath === "/authorize") {
2943
- const clientId = url.searchParams.get("client_id");
2944
- const redirectUri = url.searchParams.get("redirect_uri");
2945
- const state = url.searchParams.get("state");
2946
- const codeChallenge = url.searchParams.get("code_challenge");
2947
- const codeChallengeMethod = url.searchParams.get("code_challenge_method");
2948
-
2949
- if (!clientId || !redirectUri) {
2950
- res.writeHead(400, { "Content-Type": "text/plain", ...CORS });
2951
- return res.end("Missing client_id or redirect_uri");
2952
- }
2953
-
2954
- const code = crypto.randomBytes(32).toString("hex");
2955
- oauthCodes.set(code, {
2956
- client_id: clientId, redirect_uri: redirectUri,
2957
- code_challenge: codeChallenge, code_challenge_method: codeChallengeMethod,
2958
- expires: Date.now() + 300_000,
2959
- });
2960
-
2961
- const redirect = new URL(redirectUri);
2962
- redirect.searchParams.set("code", code);
2963
- if (state) redirect.searchParams.set("state", state);
2964
-
2965
- const logMsg = `[${new Date().toISOString()}] OAuth: authorize → code issued for ${clientId}, redirecting to ${redirect.origin}\n`;
2966
- try { fs.appendFileSync(LOG_FILE, logMsg); } catch {}
2967
- res.writeHead(302, { Location: redirect.toString(), ...CORS });
2968
- return res.end();
2881
+ // ── OAuth Discovery — disabled (causes claude.ai OAuth loop) ──────────────
2882
+ if (reqPath.startsWith("/.well-known/oauth-protected-resource") ||
2883
+ reqPath === "/.well-known/oauth-authorization-server") {
2884
+ res.writeHead(404, { "Content-Type": "application/json", ...CORS });
2885
+ return res.end(JSON.stringify({ error: "not_found" }));
2969
2886
  }
2970
2887
 
2971
- // ── Token endpoint ──────────────────────────────────────
2972
- if (method === "POST" && reqPath === "/token") {
2973
- let body;
2974
- const ct = req.headers["content-type"] || "";
2975
- try {
2976
- if (ct.includes("application/json")) {
2977
- body = await readBody(req);
2978
- } else {
2979
- const raw = await readRawBody(req);
2980
- body = Object.fromEntries(new URLSearchParams(raw));
2981
- }
2982
- } catch {
2983
- res.writeHead(400, { "Content-Type": "application/json", ...CORS });
2984
- return res.end(JSON.stringify({ error: "invalid_request" }));
2985
- }
2986
-
2987
- if (body.grant_type !== "authorization_code") {
2988
- res.writeHead(400, { "Content-Type": "application/json", ...CORS });
2989
- return res.end(JSON.stringify({ error: "unsupported_grant_type" }));
2990
- }
2991
-
2992
- const stored = oauthCodes.get(body.code);
2993
- if (!stored || stored.expires < Date.now()) {
2994
- oauthCodes.delete(body.code);
2995
- res.writeHead(400, { "Content-Type": "application/json", ...CORS });
2996
- return res.end(JSON.stringify({ error: "invalid_grant" }));
2997
- }
2998
-
2999
- // PKCE verification
3000
- if (stored.code_challenge && body.code_verifier) {
3001
- const computed = sha256base64url(body.code_verifier);
3002
- if (computed !== stored.code_challenge) {
3003
- oauthCodes.delete(body.code);
3004
- res.writeHead(400, { "Content-Type": "application/json", ...CORS });
3005
- return res.end(JSON.stringify({ error: "invalid_grant", error_description: "PKCE verification failed" }));
3006
- }
3007
- }
3008
-
3009
- oauthCodes.delete(body.code);
3010
- const accessToken = crypto.randomBytes(32).toString("hex");
3011
- oauthTokens.add(accessToken);
3012
- saveTokens(oauthTokens);
3013
-
3014
- const logMsg = `[${new Date().toISOString()}] OAuth: token issued for client ${stored.client_id}\n`;
3015
- try { fs.appendFileSync(LOG_FILE, logMsg); } catch {}
3016
- res.writeHead(200, { "Content-Type": "application/json", ...CORS });
3017
- return res.end(JSON.stringify({ access_token: accessToken, token_type: "Bearer", expires_in: 86400 }));
2888
+ // ── OAuth endpoints — disabled (well-known removed, these are dead paths) ──
2889
+ if ((method === "POST" && reqPath === "/register") ||
2890
+ (method === "GET" && reqPath === "/authorize") ||
2891
+ (method === "POST" && reqPath === "/token")) {
2892
+ res.writeHead(404, { "Content-Type": "application/json", ...CORS });
2893
+ return res.end(JSON.stringify({ error: "not_found" }));
3018
2894
  }
3019
2895
 
3020
2896
  // ── MCP path helpers ──
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lifeaitools/clauth",
3
- "version": "1.5.16",
3
+ "version": "1.5.18",
4
4
  "description": "Hardware-bound credential vault for the LIFEAI infrastructure stack",
5
5
  "type": "module",
6
6
  "bin": {