From adbaffe545692e4d382cb877d1d5c9cd02c80ef7 Mon Sep 17 00:00:00 2001 From: Colin Maudry Date: Mon, 13 Jul 2026 13:48:42 +0200 Subject: [PATCH] =?UTF-8?q?feat(mcp):=20store=20OAuth=20=E2=80=94=20codes?= =?UTF-8?q?=20d'autorisation=20(#114)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- src/mcp/oauth/store.py | 47 +++++++++++++++++++++++++++++++++++ tests/mcp/test_oauth_store.py | 23 +++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/src/mcp/oauth/store.py b/src/mcp/oauth/store.py index 2d63403..829be0f 100644 --- a/src/mcp/oauth/store.py +++ b/src/mcp/oauth/store.py @@ -88,3 +88,50 @@ def get_client(db_path, client_id: str) -> dict | None: d = dict(row) d["client_metadata"] = json.loads(d["client_metadata"]) return d + + +def save_code( + db_path, + code: str, + *, + client_id: str, + user_id: int, + redirect_uri: str | None, + code_challenge: str | None, + code_challenge_method: str | None, + scope: str | None, + resource: str | None, + expires_at: str, +) -> None: + with _connect(db_path) as conn: + conn.execute( + "INSERT INTO oauth_codes (code_hash, client_id, user_id, redirect_uri, " + "code_challenge, code_challenge_method, scope, resource, expires_at) " + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", + ( + _hash(code), + client_id, + user_id, + redirect_uri, + code_challenge, + code_challenge_method, + scope, + resource, + expires_at, + ), + ) + conn.commit() + + +def get_code(db_path, code: str) -> dict | None: + with _connect(db_path) as conn: + row = conn.execute( + "SELECT * FROM oauth_codes WHERE code_hash = ?", (_hash(code),) + ).fetchone() + return dict(row) if row else None + + +def delete_code(db_path, code: str) -> None: + with _connect(db_path) as conn: + conn.execute("DELETE FROM oauth_codes WHERE code_hash = ?", (_hash(code),)) + conn.commit() diff --git a/tests/mcp/test_oauth_store.py b/tests/mcp/test_oauth_store.py index bca7a65..28b482c 100644 --- a/tests/mcp/test_oauth_store.py +++ b/tests/mcp/test_oauth_store.py @@ -13,3 +13,26 @@ def test_create_and_get_client(tmp_path): assert row["client_id"] == "abc123" assert row["client_metadata"] == meta assert store.get_client(db, "nope") is None + + +def test_save_get_delete_code(tmp_path): + db = tmp_path / "u.sqlite" + store.init_schema(db) + store.save_code( + db, + "thecode", + client_id="abc", + user_id=7, + redirect_uri="https://claude.ai/api/mcp/auth_callback", + code_challenge="chal", + code_challenge_method="S256", + scope="mcp", + resource="https://colibre.fr/_mcp", + expires_at="2999-01-01T00:00:00+00:00", + ) + row = store.get_code(db, "thecode") + assert row["user_id"] == 7 + assert row["code_challenge"] == "chal" + assert row["resource"] == "https://colibre.fr/_mcp" + store.delete_code(db, "thecode") + assert store.get_code(db, "thecode") is None