Environment
- DevSpace: v1.0.2
- Node: v24.15.0
- OS: macOS arm64
- Tunnel: Cloudflare Tunnel (Named Tunnel)
- MCP SDK:
@modelcontextprotocol/sdk@1.13.4
Problem Description
After a fresh reinstall of DevSpace 1.0.2, OAuth clients database is empty and ChatGPT reconnection fails at the token exchange step with:
{"error":"invalid_client","error_description":"Client secret is required"}
This happens despite the client being registered with token_endpoint_auth_method: "none" (public client, as required by ChatGPT web connector).
Root Cause Analysis
The issue is in MCP SDK v1.13.4 (@modelcontextprotocol/sdk/dist/*/server/auth/middleware/clientAuth.js).
When the client is registered with token_endpoint_auth_method: "none", the authenticateClient middleware still checks for client_secret in the token request body:
// clientAuth.js ~line 19
if (client.client_secret) {
// Validates client_secret even when token_endpoint_auth_method === "none"
}
This causes the token exchange to fail for public clients (like ChatGPT's web-based OAuth connector) that legitimately do not have a client secret.
Steps to Reproduce
- Fresh install DevSpace 1.0.2:
npm install -g @waishnav/devspace
- Configure with cloudflared tunnel:
publicBaseUrl: "https://devspace.trendxai.io"
- Add
logging: { trustProxy: true } to ~/.devspace/config.json (fixes the separate express-rate-limit issue)
- Restart devspace
- In ChatGPT, add MCP server:
https://devspace.trendxai.io/mcp
- ChatGPT registers a new OAuth client (via
/register) with token_endpoint_auth_method: "none"
- User approves with Owner Password → authorization code is returned
- Token exchange fails with
{"error":"invalid_client","error_description":"Client secret is required"}
Verification
Direct curl reproduction:
# Register client (returns token_endpoint_auth_method: "none")
CLIENT=$(curl -s -X POST https://devspace.trendxai.io/register \
-H "Content-Type: application/json" \
-d '{"redirect_uris": ["https://chatgpt.com/connector/oauth/test"], "client_name": "ChatGPT"}')
CLIENT_ID=$(echo $CLIENT | jq -r '.client_id')
# Authorize (returns code)
CODE=$(curl -s -X POST "https://devspace.trendxai.io/authorize?client_id=$CLIENT_ID&..." \
-d "owner_token=YOUR_OWNER_TOKEN" \
-i | grep -o 'code=[^&]*' | cut -d'=' -f2)
# Token exchange (FAILS - requires client_secret even though method is "none")
curl -s -X POST https://devspace.trendxai.io/token \
-d "grant_type=authorization_code" \
-d "code=$CODE" \
-d "client_id=$CLIENT_ID" \
-d "code_verifier=abc123"
# → {"error":"invalid_client","error_description":"Client secret is required"}
Related Issue
This is related to #5 (express-rate-limit with reverse proxy), which was fixed by setting DEVSPACE_TRUST_PROXY=true. But after fixing the trust proxy issue, this new token exchange bug blocks the connection entirely.
Expected Behavior
When token_endpoint_auth_method is "none", the token endpoint should NOT require a client_secret parameter during the authorization_code grant exchange. This is the standard OAuth 2.0 behavior for public clients (PKCE-only).
Suggested Fix
In clientAuth.js, the authenticateClient middleware should check client.token_endpoint_auth_method before requiring client_secret:
// Only validate client_secret if token_endpoint_auth_method requires it
if (client.client_secret && client.token_endpoint_auth_method !== "none") {
// Validate client_secret
}
Alternatively, this may need to be fixed upstream in the MCP SDK (@modelcontextprotocol/typescript-sdk), and DevSpace should upgrade to the fixed version.
Additional Context
- This was working previously (before the reinstall). The issue only appears after the OAuth clients database is cleared and ChatGPT re-registers.
- The same
invalid_client error also manifests as Invalid client_id in some cases when the client registration data is malformed.
- The
clientRegistrationHandler in the SDK also has a related bug: it checks clientMetadata.token_endpoint_auth_method to decide whether to generate client_secret, but the condition if (!clientMetadata.token_endpoint_auth_method || clientMetadata.token_endpoint_auth_method === "client_secret_post") will generate a secret even when the method is explicitly set to "none" (if the condition is mis-evaluated).
Environment
@modelcontextprotocol/sdk@1.13.4Problem Description
After a fresh reinstall of DevSpace 1.0.2, OAuth clients database is empty and ChatGPT reconnection fails at the token exchange step with:
{"error":"invalid_client","error_description":"Client secret is required"}This happens despite the client being registered with
token_endpoint_auth_method: "none"(public client, as required by ChatGPT web connector).Root Cause Analysis
The issue is in MCP SDK v1.13.4 (
@modelcontextprotocol/sdk/dist/*/server/auth/middleware/clientAuth.js).When the client is registered with
token_endpoint_auth_method: "none", theauthenticateClientmiddleware still checks forclient_secretin the token request body:This causes the token exchange to fail for public clients (like ChatGPT's web-based OAuth connector) that legitimately do not have a client secret.
Steps to Reproduce
npm install -g @waishnav/devspacepublicBaseUrl: "https://devspace.trendxai.io"logging: { trustProxy: true }to~/.devspace/config.json(fixes the separate express-rate-limit issue)https://devspace.trendxai.io/mcp/register) withtoken_endpoint_auth_method: "none"{"error":"invalid_client","error_description":"Client secret is required"}Verification
Direct curl reproduction:
Related Issue
This is related to #5 (express-rate-limit with reverse proxy), which was fixed by setting
DEVSPACE_TRUST_PROXY=true. But after fixing the trust proxy issue, this new token exchange bug blocks the connection entirely.Expected Behavior
When
token_endpoint_auth_methodis"none", the token endpoint should NOT require aclient_secretparameter during the authorization_code grant exchange. This is the standard OAuth 2.0 behavior for public clients (PKCE-only).Suggested Fix
In
clientAuth.js, theauthenticateClientmiddleware should checkclient.token_endpoint_auth_methodbefore requiringclient_secret:Alternatively, this may need to be fixed upstream in the MCP SDK (
@modelcontextprotocol/typescript-sdk), and DevSpace should upgrade to the fixed version.Additional Context
invalid_clienterror also manifests asInvalid client_idin some cases when the client registration data is malformed.clientRegistrationHandlerin the SDK also has a related bug: it checksclientMetadata.token_endpoint_auth_methodto decide whether to generateclient_secret, but the conditionif (!clientMetadata.token_endpoint_auth_method || clientMetadata.token_endpoint_auth_method === "client_secret_post")will generate a secret even when the method is explicitly set to"none"(if the condition is mis-evaluated).