Coverage for src/lexigram/auth/web/middleware/api_key_authenticator.py: 48%

21 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-26 00:58 +0800

1"""API key authentication component.""" 

2 

3from __future__ import annotations 

4 

5from typing import Any 

6 

7from lexigram.contracts import AuthProviderProtocol 

8 

9 

10class ApiKeyAuthenticator: 

11 """Handles API key validation and user resolution.""" 

12 

13 def __init__(self, auth_provider: AuthProviderProtocol): 

14 self.auth_provider = auth_provider 

15 

16 async def authenticate(self, token: str, request: Any) -> Any: 

17 """Validate API key and return user if valid.""" 

18 if not token.startswith("sk_"): 

19 return None 

20 

21 if not self.auth_provider.api_key_manager: 

22 return None 

23 

24 api_key = await self.auth_provider.api_key_manager.validate_key( 

25 token, 

26 ip_address=getattr(request.client, "host", None), 

27 ) 

28 if not api_key or not api_key.user_id: 

29 return None 

30 

31 user = await self.auth_provider.get_user(api_key.user_id) 

32 if not user: 

33 return None 

34 

35 # Pre-fetch delegations for sync check_access 

36 if self.auth_provider.delegation_manager: 

37 request.state.delegations = ( 

38 await self.auth_provider.delegation_manager.get_active_delegations( 

39 user.user_id, 

40 ) 

41 ) 

42 

43 return user 

44 

45 

46__all__ = [ 

47 "ApiKeyAuthenticator", 

48]