agentscope-ai / agentscope-ai/QwenPaw

[Bug]: QwenPaw's MCP OAuth implementation does not support sending client_secret during the token exchange step.

Abierto
#4,643 1 comentario 1 reacción 1 asignado Reclamado por @rayrayraykk Ver en GitHub
bug
Lenguaje dominante
Python
Estrellas
34.9k
Forks
3.1k
Merge medio
1 d 15 h
PR fusionados (30 d)
225

Descripción

## QwenPaw Version

v1.1.8.post1

## Description

QwenPaw's MCP OAuth implementation does not support sending `client_secret` during the token exchange step. This makes it impossible to connect to MCP servers that require confidential OAuth 2.0 clients — including providers that do not implement Dynamic Client Registration (RFC 7591), such as **Google Workspace MCP** (Gmail/Drive/Calendar/Chat).

The OAuth flow proceeds correctly up to the authorization step: the user is redirected to the provider, signs in, consents to scopes, and is redirected back to `/api/mcp/oauth/callback` with a valid `code` and `state`. The token exchange then fails because Google's `https://oauth2.googleapis.com/token` endpoint requires `client_secret` for Web Application OAuth clients, and QwenPaw does not include it in the POST body.

The `MCPOAuthConfig` schema in `src/qwenpaw/config/config.py` has no `client_secret` field, the `OAuthStartRequest` in `src/qwenpaw/app/routers/mcp_oauth.py` does not accept it, and `_exchange_code_for_tokens` does not send it.

**Related PR(s):** #4532 (this PR adds `client_secret` to the schema as part of a larger OAuth 2.1 rewrite, but is currently OPEN, CONFLICTING with main, and has not landed)

**Security considerations:** `client_secret` is sensitive credential material and should not be required to live as plaintext in `agent.json` alongside the access token. Recommended approach:

Support reading `client_secret` from an environment variable (e.g. `QWENPAW_MCP__CLIENT_SECRET`), following the pattern already used elsewhere in QwenPaw for sensitive provider credentials. This keeps the secret out of the workspace directory entirely and aligns with standard 12-factor / container deployment patterns.

## Component(s) Affected

- [x] MCP

## Environment

- **QwenPaw version:** Latest stable main (post-PR #4256, pre-PR #4532)
- **OS:** Ubuntu 22.04 (LXC container)
- **Install method:** PyPI via pip in `/opt/copaw-venv`.
- **Python version (if applicable):** 3.12.3

## Steps to Reproduce

1. Register a Google Cloud OAuth 2.0 Client as "Web application" type. Note the `client_id` and `client_secret`. Register `https:///api/mcp/oauth/callback` as an authorized redirect URI.
2. In QwenPaw, add a new MCP client pointing at a Google Workspace MCP endpoint (e.g. `https://gmailmcp.googleapis.com/mcp/v1`), with transport `streamable_http`.
3. Trigger the OAuth flow with the manual override fields:
- `client_id`: your Google client_id
- `auth_endpoint`: `https://accounts.google.com/o/oauth2/v2/auth`
- `token_endpoint`: `https://oauth2.googleapis.com/token`
- `scope`: e.g. `https://www.googleapis.com/auth/gmail.readonly`
4. Sign in with Google and approve consent.
5. Google redirects back to `/api/mcp/oauth/callback` with valid `code` and `state`.
6. QwenPaw attempts the token exchange.

## Actual vs Expected

- **Actual:** The OAuth popup shows "Authorization failed" with the body:
Token exchange failed (HTTP 400): { "error": "invalid_request", "error_description": "client_secret is missing." }

No tokens are persisted to `agent.json`. The MCP client cannot connect.
- **Expected:** QwenPaw should send `client_secret` in the token exchange POST body when configured, allowing the flow to complete and tokens to be persisted. This is standard behavior for OAuth 2.0 confidential clients (RFC 6749 §2.3) and is required by Google, HubSpot, Microsoft Graph, and other providers that do not implement RFC 7591 Dynamic Client Registration.
## Logs / Screenshots
Token exchange error as returned by Google's authorization server, shown in the QwenPaw OAuth callback popup:
Token exchange failed (HTTP 400): {
"error": "invalid_request",
"error_description": "client_secret is missing."
}

The browser-side `redirect_uri` parameter received by Google included a valid PKCE `code_challenge` and `state`, confirming the flow reaches the token exchange step before failing.
## Additional Notes
- **Workaround:** A minimal local patch (~15 lines across `src/qwenpaw/config/config.py` and `src/qwenpaw/app/routers/mcp_oauth.py`) adds `client_secret` to `MCPOAuthConfig`, `OAuthStartRequest`, `OAuthSession`, and includes it conditionally in the token exchange `data` dict. Hand-editing `agent.json` to pre-populate `oauth.client_secret` works around the missing UI field.
- **Why this matters now:** Google Workspace MCP launched in developer preview in May 2026 and is one of the most prominent remote MCP integrations being adopted. The current implementation in main supports DCR-compatible providers (Cloudflare, Linear) but silently fails against any provider that requires pre-registered confidential clients. PR #4532 addresses this as a side effect of a larger rewrite, but a smaller focused fix could land sooner.

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.