diff --git a/src/services/api_key_service.py b/src/services/api_key_service.py index 92879cb58..561931381 100644 --- a/src/services/api_key_service.py +++ b/src/services/api_key_service.py @@ -237,7 +237,7 @@ async def list_keys( jwt_token: str = None, ) -> dict[str, Any]: """ - List all API keys for a user (without the actual keys). + List all active (non-revoked) API keys for a user (without the actual keys). Args: user_id: The user's ID @@ -251,7 +251,14 @@ async def list_keys( # Search for user's keys search_body = { - "query": {"term": {"user_id": user_id}}, + "query": { + "bool": { + "must": [ + {"term": {"user_id": user_id}}, + {"term": {"revoked": False}}, + ] + } + }, "sort": [{"created_at": {"order": "desc"}}], "_source": [ "key_id", diff --git a/tests/unit/test_api_key_service.py b/tests/unit/test_api_key_service.py index f1de9f058..ace11d0c5 100644 --- a/tests/unit/test_api_key_service.py +++ b/tests/unit/test_api_key_service.py @@ -92,3 +92,47 @@ async def test_validate_key_accepts_and_migrates_legacy_hash(monkeypatch): update_doc = opensearch_client.update.await_args.kwargs["body"]["doc"] assert update_doc["key_hash"] == keyed_hash assert "last_used_at" in update_doc + + +@pytest.mark.asyncio +async def test_list_keys_returns_only_non_revoked_api_keys(monkeypatch) -> None: + from services.api_key_service import APIKeyService + + service = APIKeyService() + + opensearch_client = AsyncMock() + opensearch_client.search.return_value = { + "hits": { + "hits": [ + { + "_source": { + "key_id": "key-1", + "key_prefix": "orag_aaaaaaaa", + "name": "active key", + "created_at": "2026-06-15T10:03:58.016280", + "last_used_at": None, + "revoked": False, + } + }, + ] + } + } + monkeypatch.setattr("config.settings.clients.opensearch", opensearch_client) + + result = await service.list_keys(user_id="user-1") + + assert result["success"] is True + assert result["keys"] == [ + { + "key_id": "key-1", + "key_prefix": "orag_aaaaaaaa", + "name": "active key", + "created_at": "2026-06-15T10:03:58.016280", + "last_used_at": None, + "revoked": False, + } + ] + + query_must = opensearch_client.search.await_args.kwargs["body"]["query"]["bool"]["must"] + assert {"term": {"user_id": "user-1"}} in query_must + assert {"term": {"revoked": False}} in query_must