Conversation
813fe0b to
293c5e4
Compare
b1ba1d8 to
e400049
Compare
- EveryRowAuthProvider: full OAuth 2.1 AS with 3-leg PKCE chain (Google -> Supabase -> MCP Server -> Claude) - SupabaseTokenVerifier: JWKS-based JWT verification with token deny-list - Redis-backed storage for auth codes, refresh tokens, client registrations - Atomic GETDEL operations to prevent token replay/race conditions - Per-IP rate limiting on handle_start and handle_callback routes - Access token revocation via deny-list integration - Scope narrowing on refresh per OAuth 2.1 spec - Input length validation on auth codes and refresh tokens - Unconditional redirect_uri validation - JWKS fetch timeout (10s) to prevent lock contention - All TTLs and rate limits configurable via pydantic-settings with bounds validation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
e400049 to
746a40e
Compare
…ttpSettings Replace all self._settings / self.supabase_url / self.mcp_server_url / self.supabase_anon_key references in EveryRowAuthProvider with the http_settings module-level singleton from config.py. Add _strip_trailing_slash field validator to HttpSettings for URL fields. Simplify constructor to only take redis + token_verifier. Update tests to match. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add back from __future__ import annotations (fixes Python 3.12 CI) - Make _supabase_redirect_url and _validate_redirect_url @staticmethod - Extract _supabase_token_request to DRY _exchange_supabase_code / _refresh_supabase_token - Extract _create_authorisation_code and _create_callback_redirect_response - Hardcode secure=True on auth cookies - Type pending param in _create_callback_redirect_response Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract _is_revoked, _get_signing_key, _decode_jwt from verify_token - Keep deny-list check after JWT verification (avoid Redis hit on garbage tokens) - Extract _issue_token_response to DRY exchange_authorization_code / exchange_refresh_token - Extract _create_authorisation_code and _create_callback_redirect_response - Hardcode secure=True on auth cookies Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Contributor
Author
|
Migration to Supabase OAuth 2.1 This auth module currently implements a PKCE relay: we sit between Claude and Supabase, generating our own PKCE pair for the Supabase leg and managing auth codes / refresh tokens in Redis. Supabase is working on native OAuth 2.1 support, which would let Claude talk directly to Supabase as the authorization server — eliminating the relay and most of this module. Not yet viable for two reasons:
|
7 tasks
Contributor
|
OK, looks good! Some claude's code review, which I think is valid but I don't see us doing these suggestions, it's good. Details |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
EveryRowAuthProviderimplementing the full OAuth 2.1 Authorization Server flow (dynamic client registration, PKCE authorization, token exchange/refresh) with user login delegated to Supabase Google OAuthSupabaseTokenVerifierfor JWKS-based JWT verification with a Redis-backed token deny-listhttp_settingssingleton fromconfig.py; URL fields are stripped of trailing slashes viaHttpSettingsvalidatorPyJWT[crypto]andhttpxas dependencies; usesTYPE_CHECKINGimport forredis.asyncioto keep stdio mode lightweightNew files
everyrow-mcp/src/everyrow_mcp/auth.py— OAuth provider + token verifier (540 lines)everyrow-mcp/tests/test_auth.py— 31 tests covering JWT verification, deny-list propagation, required claims, JWKS lock concurrency, atomic code consumption, scope narrowing, redirect URI validation, rate limiting, token revocation, client ID mismatch, and input length validation (717 lines)Key design decisions
http_settingssingleton (not passed via constructor) — provider methods referencehttp_settings.*directly_issue_token_responseshared helper — DRYsexchange_authorization_codeandexchange_refresh_token_supabase_token_requestshared helper — DRYs the two Supabase/tokencallsaclose()on provider for clean httpx shutdownsecure=True(HTTPS-only in production)PR context
PR 3 of 5 in the HTTP transport split. Depends on PR1 (#179, foundation utilities) and PR2 (#180, Redis infrastructure), both already merged. Does not touch
app.py,tools.py,server.py, ormodels.py.Test plan
uv run pytest tests/ -x)config.py,redis_utils.py)🤖 Generated with Claude Code