Coverage for nexios\auth\backends\apikey.py: 41%

17 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-05-21 20:31 +0100

1from typing import Any, Callable, Awaitable 

2from typing_extensions import Annotated, Doc 

3from nexios.auth.base import AuthenticationBackend, UnauthenticatedUser 

4from nexios.http import Request, Response 

5 

6 

7class APIKeyAuthBackend(AuthenticationBackend): 

8 """ 

9 Authentication backend for API key-based authentication. 

10 

11 This class verifies incoming requests using API keys found in request headers. 

12 It relies on a user-defined authentication function to validate API keys. 

13 

14 Attributes: 

15 authenticate_func (Callable[..., Awaitable[Any]]): The function used to validate API keys. 

16 header_name (str): The HTTP header used to pass the API key (default: "X-API-Key"). 

17 """ 

18 

19 def __init__( 

20 self, 

21 authenticate_func: Annotated[ 

22 Callable[..., Awaitable[Any]], 

23 Doc( 

24 "Function that takes an API key and returns a user object if valid, None otherwise." 

25 ), 

26 ], 

27 header_name: Annotated[ 

28 str, 

29 Doc( 

30 'The header name from which the API key is retrieved (default: "X-API-Key").' 

31 ), 

32 ] = "X-API-Key", 

33 ) -> None: 

34 """ 

35 Initializes the APIKeyAuthBackend with an authentication function and optional header name. 

36 

37 Args: 

38 authenticate_func (Callable[..., Awaitable[Any]]): Function to validate API keys. 

39 header_name (str, optional): Header key where the API key is expected (default: "X-API-Key"). 

40 """ 

41 self.authenticate_func = authenticate_func 

42 self.header_name = header_name 

43 

44 async def authenticate( # type: ignore[override] 

45 self, 

46 request: Annotated[ 

47 Request, 

48 Doc( 

49 "The incoming HTTP request, containing authentication credentials in headers." 

50 ), 

51 ], 

52 response: Annotated[ 

53 Response, 

54 Doc( 

55 "The HTTP response object, which may be modified for authentication-related headers." 

56 ), 

57 ], 

58 ) -> Any: 

59 """ 

60 Authenticates the request by checking for an API key in the specified header. 

61 

62 This method extracts the API key from the request headers and verifies it 

63 using the provided authentication function. 

64 

65 Args: 

66 request (Request): The incoming HTTP request. 

67 response (Response): The response object (may be modified). 

68 

69 Returns: 

70 Any: A user object if authentication is successful, `UnauthenticatedUser` if invalid, or `None` if no API key is provided. 

71 

72 Side Effects: 

73 - If no API key is found, sets the `WWW-Authenticate` response header. 

74 """ 

75 # Retrieve the API key from the request headers 

76 api_key = request.headers.get(self.header_name) 

77 if not api_key: 

78 response.set_header("WWW-Authenticate", 'APIKey realm="Access to the API"') 

79 return None 

80 

81 # Authenticate the API key using the provided function 

82 user = await self.authenticate_func(api_key) 

83 if not user: 

84 return UnauthenticatedUser() 

85 

86 return user, "apikey"