Skip to content

feat(auth): add OAuth 2.1 for remote MCP deployments#2

Merged
5queezer merged 9 commits into
mainfrom
feature/231-oauth-auth
Mar 19, 2026
Merged

feat(auth): add OAuth 2.1 for remote MCP deployments#2
5queezer merged 9 commits into
mainfrom
feature/231-oauth-auth

Conversation

@5queezer
Copy link
Copy Markdown
Owner

Summary

Test plan

  • Unit tests pass
  • Security review completed

5queezer and others added 9 commits March 19, 2026 21:22
Add opt-in OAuth 2.1 authentication behind `--auth oauth` for remote
server deployments. Subclasses FastMCP's InMemoryOAuthProvider to add a
password-based login page in the /authorize flow, enabling claude.ai
custom connector integration via Dynamic Client Registration.

- PasswordOAuthProvider with HTML login page and brute-force lockout
- OAuthConfig dataclass with validation (skipped for --login/--status/--logout)
- AUTH, OAUTH_BASE_URL, OAUTH_PASSWORD env vars and CLI args
- Integration tests verifying 401→discovery and .well-known endpoints
- Documentation in README, docker-hub.md, and manifest.json

Closes stickerdaniel#231

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds X-Frame-Options: DENY, Content-Security-Policy with frame-ancestors
'none', and X-Content-Type-Options: nosniff to all login page responses.
Prevents clickjacking attacks on the password form.

Found by OAuth 2.1 penetration test (W1, W2 in PR stickerdaniel#233 report).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Claude.ai sends requests to the root path by default, which returns 404.
Make it unmistakable that the full MCP endpoint URL is required.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nt, assert removal

- Add global rate limiter (20 failures / 5 min window → 60s lockout) to
  prevent brute-force bypass via fresh request_ids
- Enforce TTL at form submission time, not only during cleanup
- Replace assert with explicit ValueError for oauth_config guards
- Document single-instance requirement for in-memory OAuth state

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Apply greptile suggestion

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
- Add restart guidance to 429 global lockout message (prevents dead-end
  when per-request + global lockout collide simultaneously)
- Add restart guidance to "Client not found" error message
- Validate base_url has no path component in _validate_oauth (prevents
  silent 404 when base_url contains e.g. /api)
- Add tests for HTTPS validation, path-component rejection, and
  trailing-slash acceptance

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ering

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@5queezer 5queezer merged commit d2c819e into main Mar 19, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant