Coverage for nexios\auth\base.py: 76%
38 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-21 20:31 +0100
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-21 20:31 +0100
1from __future__ import annotations
2import typing
3from typing_extensions import Annotated, Doc
4from nexios.http import Request, Response
7class AuthenticationError(Exception):
8 """
9 Exception raised when authentication fails.
11 This error is triggered when an authentication backend determines that
12 the provided credentials are invalid or the authentication process
13 encounters an unexpected issue.
14 """
16 pass
19class AuthCredentials:
20 def __init__(self, scopes: typing.Optional[typing.Sequence[str]] = None):
21 self.scopes = [] if scopes is None else list(scopes)
24class AuthenticationBackend:
25 """
26 Base class for authentication backends in Nexios.
28 Authentication backends are responsible for verifying user credentials
29 and returning an authenticated user instance if authentication is successful.
31 Subclasses must override `authenticate()` to implement custom authentication logic.
32 """
34 async def authenticate(
35 self,
36 req: Annotated[
37 Request, Doc("The incoming HTTP request containing authentication details.")
38 ],
39 res: Annotated[
40 Response,
41 Doc("The HTTP response object that may be modified during authentication."),
42 ],
43 ) -> Annotated[
44 typing.Any,
45 Doc("Returns an authenticated user instance or raises an AuthenticationError."),
46 ]:
47 """
48 Authenticates a user based on the request.
50 Subclasses must implement this method to verify authentication credentials
51 (e.g., headers, cookies, or tokens) and return an authenticated user instance.
53 Args:
54 req (Request): The HTTP request object.
55 res (Response): The HTTP response object.
57 Returns:
58 Any: An authenticated user object if authentication succeeds.
60 Raises:
61 AuthenticationError: If authentication fails.
62 """
63 raise NotImplementedError()
66class BaseUser:
67 """
68 Abstract base class for user objects.
70 This class defines the minimum required properties for user objects,
71 including authentication status, display name, and identity.
73 Subclasses should override these properties to provide meaningful values.
74 """
76 @property
77 def is_authenticated(
78 self,
79 ) -> Annotated[bool, Doc("Indicates whether the user is authenticated.")]:
80 """
81 Checks if the user is authenticated.
83 This property should be overridden in subclasses to return `True` for
84 authenticated users and `False` for unauthenticated users.
86 Returns:
87 bool: `True` if the user is authenticated, otherwise `False`.
88 """
89 raise NotImplementedError()
91 @property
92 def display_name(
93 self,
94 ) -> Annotated[str, Doc("The name to be displayed for the user.")]:
95 """
96 Retrieves the display name of the user.
98 This property should be overridden to return a human-readable
99 name for authenticated users or an empty string for unauthenticated users.
101 Returns:
102 str: The display name of the user.
103 """
104 raise NotImplementedError()
106 @property
107 def identity(
108 self,
109 ) -> Annotated[
110 str, Doc("A unique identifier for the user, such as a username or ID.")
111 ]:
112 """
113 Retrieves the unique identity of the user.
115 This property should be overridden to return a unique identifier
116 (e.g., username, email, or user ID).
118 Returns:
119 str: The unique identifier of the user.
120 """
121 raise NotImplementedError()
124class SimpleUser(BaseUser):
125 """
126 A basic implementation of an authenticated user.
128 This class represents a simple authenticated user with a username.
129 """
131 def __init__(
132 self, username: Annotated[str, Doc("The username of the authenticated user.")]
133 ) -> None:
134 """
135 Initializes a simple authenticated user.
137 Args:
138 username (str): The username of the user.
139 """
140 self.username = username
142 @property
143 def is_authenticated(
144 self,
145 ) -> Annotated[
146 bool, Doc("Always returns `True` since this user is authenticated.")
147 ]:
148 """
149 Indicates that the user is authenticated.
151 Returns:
152 bool: Always `True` since this represents an authenticated user.
153 """
154 return True
156 @property
157 def display_name(
158 self,
159 ) -> Annotated[str, Doc("Returns the username as the display name.")]:
160 """
161 Retrieves the display name of the user.
163 Returns:
164 str: The username of the authenticated user.
165 """
166 return self.username
169class UnauthenticatedUser(BaseUser):
170 """
171 Represents an unauthenticated user.
173 This class is used to represent users who have not logged in.
174 """
176 @property
177 def is_authenticated(
178 self,
179 ) -> Annotated[
180 bool, Doc("Always returns `False` since this user is unauthenticated.")
181 ]:
182 """
183 Indicates that the user is not authenticated.
185 Returns:
186 bool: Always `False` since this represents an unauthenticated user.
187 """
188 return False
190 @property
191 def display_name(
192 self,
193 ) -> Annotated[
194 str,
195 Doc(
196 "Returns an empty string since unauthenticated users have no display name."
197 ),
198 ]:
199 """
200 Retrieves the display name of the user.
202 Since unauthenticated users do not have a valid username, this
203 method returns an empty string.
205 Returns:
206 str: An empty string.
207 """
208 return ""