@lifeaitools/clauth 1.5.24 → 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 +29 -6
- package/package.json +1 -1
package/cli/commands/serve.js
CHANGED
|
@@ -2962,7 +2962,7 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
2962
2962
|
token_endpoint: `${base}/token`,
|
|
2963
2963
|
registration_endpoint: `${base}/register`,
|
|
2964
2964
|
response_types_supported: ["code"],
|
|
2965
|
-
grant_types_supported: ["authorization_code"],
|
|
2965
|
+
grant_types_supported: ["authorization_code", "client_credentials"],
|
|
2966
2966
|
code_challenge_methods_supported: ["S256"],
|
|
2967
2967
|
scopes_supported: ["mcp:tools"],
|
|
2968
2968
|
}));
|
|
@@ -3038,6 +3038,23 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3038
3038
|
return res.end(JSON.stringify({ error: "invalid_request" }));
|
|
3039
3039
|
}
|
|
3040
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
|
+
|
|
3041
3058
|
if (body.grant_type !== "authorization_code") {
|
|
3042
3059
|
res.writeHead(400, { "Content-Type": "application/json", ...CORS });
|
|
3043
3060
|
return res.end(JSON.stringify({ error: "unsupported_grant_type" }));
|
|
@@ -3114,15 +3131,20 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3114
3131
|
return res.end(JSON.stringify({ error: "unauthorized" }));
|
|
3115
3132
|
}
|
|
3116
3133
|
const token = authHeader.slice(7);
|
|
3117
|
-
|
|
3118
|
-
|
|
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`;
|
|
3119
3138
|
try { fs.appendFileSync(LOG_FILE, logMsg); } catch {}
|
|
3120
3139
|
res.writeHead(401, { "Content-Type": "application/json", ...CORS });
|
|
3121
3140
|
return res.end(JSON.stringify({ error: "invalid_token" }));
|
|
3122
3141
|
}
|
|
3123
3142
|
req._clauthRemote = true;
|
|
3124
|
-
} else if (authHeader?.startsWith("Bearer ")
|
|
3125
|
-
|
|
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
|
+
}
|
|
3126
3148
|
}
|
|
3127
3149
|
// fall through to MCP handling
|
|
3128
3150
|
}
|
|
@@ -3200,7 +3222,8 @@ function createServer(initPassword, whitelist, port, tunnelHostnameInit = null,
|
|
|
3200
3222
|
});
|
|
3201
3223
|
return res.end(JSON.stringify({ error: "unauthorized" }));
|
|
3202
3224
|
}
|
|
3203
|
-
|
|
3225
|
+
const sseToken = authHeader.slice(7);
|
|
3226
|
+
if (!oauthTokens.has(sseToken) && sseToken !== OAUTH_CLIENT_SECRET) {
|
|
3204
3227
|
res.writeHead(401, { "Content-Type": "application/json", ...CORS });
|
|
3205
3228
|
return res.end(JSON.stringify({ error: "invalid_token" }));
|
|
3206
3229
|
}
|