Fix client_secret not sent during OAuth token exchange#137
Conversation
When a server returns a client_secret during dynamic registration but omits token_endpoint_auth_method, the gem was defaulting to "none" and silently dropping the secret from all token requests. This breaks any MCP server that expects client_secret in the POST body (e.g. Canny). Per RFC 7591 §2, the default is "client_secret_basic", but in practice most MCP servers only support "client_secret_post". The fix: - client_registrar: infer auth method from the registration response — if client_secret is present but token_endpoint_auth_method is not, default to "client_secret_post" instead of "none" - token_manager: replace add_client_secret_if_needed with a proper apply_client_auth! that supports both client_secret_post (body) and client_secret_basic (HTTP Basic header per RFC 6749 §2.3.1) - token_manager: route all token requests (auth code, client creds, refresh) through the same auth method so the secret is always sent when it should be
|
Hi @patvice, any chance you can check this? Anyway I can make this easier for you? |
|
Confirming the same bug against a second production MCP provider, Mercury. I discovered it yesterday from a real OAuth flow in a Rails app I run. Same DCR shape as Canny: Mercury returns a client_secret in the registration response but omits Applied your patch verbatim as an initializer-level monkey-patch. Mercury connects cleanly end-to-end and the credential lifecycle completes normally. Two empirical data points worth recording:
@patvice: I would love to see this merged. Two independent production reproducers (Canny via @plehoux, Mercury via me) plus a small fix that mirrors the existing |
When a server returns a
client_secretduring dynamic registration but omitstoken_endpoint_auth_method, the gem was defaulting to"none"and silently dropping the secret from all token requests. This breaks any MCP server that expectsclient_secretin thePOSTbody (e.g. Canny).Per RFC 7591 §2, the default is
"client_secret_basic", but in practice most MCP servers only support"client_secret_post". The fix:client_registrar: infer auth method from the registration response — if client_secret is present buttoken_endpoint_auth_methodis not, default to "client_secret_post" instead of "none"token_manager: replaceadd_client_secret_if_neededwith a properapply_client_auth!that supports bothclient_secret_post(body) andclient_secret_basic(HTTP Basic header per RFC 6749 §2.3.1)token_manager: route all token requests (auth code, client creds, refresh) through the same auth method so the secret is always sent when it should beDiscovered and tested against Canny's MCP server (https://canny.io/api/mcp), which returns
client_secretduring registration but omitstoken_endpoint_auth_method. Token exchange was failing with 400 "invalid input" because the secret was never sent.To test Canny MCP server you need a paid account, but I can ask the co-founder to create you a test account.