Skip to content

Commit e58f386

Browse files
authored
Log refresh-token misses in OAuthProxy instead of failing silently (#4276)
1 parent 3f09c68 commit e58f386

2 files changed

Lines changed: 35 additions & 0 deletions

File tree

fastmcp_slim/fastmcp/server/auth/oauth_proxy/proxy.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,6 +1371,13 @@ async def load_refresh_token(
13711371
token_hash = _hash_token(refresh_token)
13721372
metadata = await self._refresh_token_store.get(key=token_hash)
13731373
if not metadata:
1374+
logger.warning(
1375+
"Refresh token not found for client=%s (token_hash=%s); it was "
1376+
"already rotated, expired, or revoked. Rejecting with invalid_grant, "
1377+
"which forces the client to re-authenticate.",
1378+
client.client_id,
1379+
token_hash[:8],
1380+
)
13741381
return None
13751382
# Verify token belongs to this client (prevents cross-client token usage)
13761383
if metadata.client_id != client.client_id:

tests/server/auth/oauth_proxy/test_tokens.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Tests for OAuth proxy token endpoint and handling."""
22

3+
import logging
34
import time
45
from unittest.mock import AsyncMock, Mock, patch
56

@@ -1883,3 +1884,30 @@ async def test_proactive_refresh_when_validated_but_within_threshold(
18831884
assert result is not None
18841885
assert result.token == "refreshed-upstream-access"
18851886
mock_oauth_client.refresh_token.assert_called_once()
1887+
1888+
1889+
class TestRefreshTokenMissLogging:
1890+
"""A refresh-token miss forces a user-visible reconnect, so it must not be silent."""
1891+
1892+
async def test_unknown_refresh_token_logs_warning(self, oauth_proxy, caplog):
1893+
client = OAuthClientInformationFull(
1894+
client_id="test-client",
1895+
client_secret="test-secret",
1896+
redirect_uris=[AnyUrl("http://localhost:12345/callback")],
1897+
)
1898+
1899+
proxy_logger = logging.getLogger("fastmcp.server.auth.oauth_proxy.proxy")
1900+
caplog.set_level(logging.WARNING)
1901+
proxy_logger.addHandler(caplog.handler)
1902+
try:
1903+
result = await oauth_proxy.load_refresh_token(client, "nonexistent-token")
1904+
finally:
1905+
proxy_logger.removeHandler(caplog.handler)
1906+
1907+
assert result is None
1908+
assert any(
1909+
record.levelno == logging.WARNING
1910+
and "Refresh token not found" in record.getMessage()
1911+
and "test-client" in record.getMessage()
1912+
for record in caplog.records
1913+
)

0 commit comments

Comments
 (0)