mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-15 06:52:04 +00:00
fix(mcp): let the consent screen return to the connecting client
After Allow on the MCP OAuth consent screen, Chromium-based browsers stayed on the page although the grant was issued. The page carried the app-wide CSP form-action 'self', and Chromium applies form-action to the redirect that follows the form post to the client's redirect_uri. The authorize route now owns the CSP of its responses and the proxy leaves that exact path alone. The consent page allows form-action for its own origin plus the origin of the redirect URI the route has just validated against the resolved client, and only https or http origins qualify. Every other response from the route keeps form-action 'self' with default-src 'none'. The redirect after the decision is now 303, which tells every browser to follow a form POST with a GET. Refs #983
This commit is contained in:
1 parent
7b7a77b292
commit
864566d882
6 files changed
+309
-10
No files matched your search
+12
-1
@@ -683,7 +683,18 @@ export function proxy(request: NextRequest) {
|
||||
isDev
|
||||
? `default-src 'self'; script-src 'self' 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; frame-src 'self' blob:; connect-src 'self'; font-src 'self';`
|
||||
: `default-src 'self'; script-src 'self' 'nonce-${nonce}'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; frame-src 'self' blob:; connect-src 'self'${aiConnectSrc}${withingsConnectSrc}${whoopConnectSrc}${stravaConnectSrc}; font-src 'self'; object-src 'none'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; worker-src 'self'; report-uri ${cspReportEndpoint}; report-to csp-endpoint;`;
|
||||
response.headers.set("Content-Security-Policy", csp);
|
||||
// The MCP OAuth authorization endpoint sets its own CSP. Its consent form
|
||||
// posts to this origin and the server then redirects to the connecting
|
||||
// client's `redirect_uri`; Chromium applies `form-action` to that redirect,
|
||||
// so the app-wide `form-action 'self'` would strand the user after the
|
||||
// grant. The route allows exactly the redirect origin it validated for the
|
||||
// request (`src/lib/mcp/oauth/consent-csp.ts`). Middleware headers override
|
||||
// route headers, so the proxy must leave the header unset on this exact
|
||||
// path; every other header above still applies.
|
||||
const isMcpAuthorizeRoute = pathname === "/api/mcp/oauth/authorize";
|
||||
if (!isMcpAuthorizeRoute) {
|
||||
response.headers.set("Content-Security-Policy", csp);
|
||||
}
|
||||
|
||||
// Production-only headers. HSTS carries `preload` so the domain stays
|
||||
// eligible for the Chromium preload list — closes the first-visit MITM
|
||||
|
||||
Reference in new issue
Block a user