SessionAuthBackend middleware was wrapping the entire app including FastMCP,
which prevented FastMCP's OAuth token verification from running properly.
When SessionAuthBackend returned None for /mcp paths, Starlette marked requests
as "anonymous" and allowed them through, bypassing FastMCP's authentication.
Changes:
1. Route restructuring (app.py):
- Create separate Starlette app for browser routes (/user, /user/page)
- Apply SessionAuthBackend only to browser app
- Mount browser app at /user/* before FastMCP
- Mount FastMCP at / (catch-all with its own OAuth)
- Remove global SessionAuthBackend middleware
2. SessionAuthBackend cleanup (session_backend.py):
- Remove path exclusion logic (no longer needed)
- Simplify to only handle browser routes
- Update docstring to reflect mount-based isolation
Benefits:
- FastMCP's OAuth token verification now runs properly
- No middleware interference between authentication mechanisms
- Clear separation: SessionAuth for browser UI, OAuth Bearer for MCP clients
- Tests confirm OAuth authentication works correctly
Testing:
- All OAuth tests pass (test_mcp_oauth_*, test_jwt_*)
- Browser routes still require session auth
- FastMCP routes use OAuth Bearer tokens exclusively
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>