fix(http): authenticate /mcp before method dispatch#1070
Conversation
Hoist authenticate/2 ahead of the HTTP method check in route_mcp/2 so every /mcp request runs the full host -> origin -> bearer pipeline regardless of method. Method dispatch now happens in dispatch_method/3 with the resolved owner. Unauthenticated GET /mcp now returns 401 (bearer challenge) instead of 405, and endpoint/method probing consumes the AuthRateLimiter. Authenticated GET still returns 405 with Allow: POST, DELETE. Verified with mix precommit in mcp_server/ (format, credo, tests). Closes #1069 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
PR Review: fix(http): authenticate /mcp before method dispatchSummaryHoists What's Good
Issues (Must Fix)None. Suggestions (Optional)None blocking. The catch-all SecurityNo concerns — this is a net security improvement. Auth/host/origin enforcement now precedes method dispatch uniformly, eliminating the unauthenticated 405 probe path. The DocumentationNo updates needed — internal refactor of private functions; no public API or DSL changes. Note on file size: VerdictApprove — clean refactor that fulfills the issue's requirements with matching test coverage and no untracked debt. |
Auto-Triage SummaryNo issues found in review — PR received an Approve verdict with no must-fix items and no blocking suggestions.
Added label. |
Hoist authenticate/2 ahead of the HTTP method check in route_mcp/2 so every /mcp request runs the full host -> origin -> bearer pipeline regardless of method. Method dispatch now happens in dispatch_method/3 with the resolved owner. Unauthenticated GET /mcp now returns 401 (bearer challenge) instead of 405, and endpoint/method probing consumes the AuthRateLimiter. Authenticated GET still returns 405 with Allow: POST, DELETE. Verified with mix precommit in mcp_server/ (format, credo, tests). Closes #1069
Summary
authenticate/2ahead of the HTTP method check inroute_mcp/2so every/mcprequest runs the full host → origin → bearer pipeline regardless of method.dispatch_method/3that receives the already-resolvedowner(POST/DELETE bodies unchanged; any other method → 405 +Allow: POST, DELETE).route_mcp/2; the inner POST/DELETE clauses keep only their method-specific error branches.Behavior change
GET /mcp→ 401 withWWW-Authenticate: Bearer(was405), so endpoint/method probing now consumes theAuthRateLimiter.GET /mcp→ still 405 withAllow: POST, DELETE.403 forbiddenbefore any 405).POST/DELETE→ unchanged.Test plan
"GET /mcp returns 405 with Allow"→"authenticated GET /mcp returns 405 with Allow"(sends auth)."unauthenticated GET /mcp returns 401 bearer challenge"."GET /mcp with bad Host returns 403 before 405".mix precommitfrommcp_server/(format, compile, credo, 529 tests, 0 failures).Closes #1069
🤖 Generated with Claude Code