Coverage for fastapi / security / api_key.py: 100%
38 statements
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-12 18:15 +0000
« prev ^ index » next coverage.py v7.13.3, created at 2026-02-12 18:15 +0000
1from typing import Annotated 1abcd
3from annotated_doc import Doc 1abcd
4from fastapi.openapi.models import APIKey, APIKeyIn 1abcd
5from fastapi.security.base import SecurityBase 1abcd
6from starlette.exceptions import HTTPException 1abcd
7from starlette.requests import Request 1abcd
8from starlette.status import HTTP_401_UNAUTHORIZED 1abcd
11class APIKeyBase(SecurityBase): 1abcd
12 def __init__( 1abcd
13 self,
14 location: APIKeyIn,
15 name: str,
16 description: str | None,
17 scheme_name: str | None,
18 auto_error: bool,
19 ):
20 self.auto_error = auto_error 1abcd
22 self.model: APIKey = APIKey( 1abcd
23 **{"in": location},
24 name=name,
25 description=description,
26 )
27 self.scheme_name = scheme_name or self.__class__.__name__ 1abcd
29 def make_not_authenticated_error(self) -> HTTPException: 1abcd
30 """
31 The WWW-Authenticate header is not standardized for API Key authentication but
32 the HTTP specification requires that an error of 401 "Unauthorized" must
33 include a WWW-Authenticate header.
35 Ref: https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized
37 For this, this method sends a custom challenge `APIKey`.
38 """
39 return HTTPException( 1efghijklmnopqrstuv
40 status_code=HTTP_401_UNAUTHORIZED,
41 detail="Not authenticated",
42 headers={"WWW-Authenticate": "APIKey"},
43 )
45 def check_api_key(self, api_key: str | None) -> str | None: 1abcd
46 if not api_key: 1FeGfHwIgJhKxLiMjNyOkPlQzRmSnTAUoVpWBXqYrZC0s1t2D3u4v5E
47 if self.auto_error: 1efwghxijyklzmnAopBqrCstDuvE
48 raise self.make_not_authenticated_error() 1efghijklmnopqrstuv
49 return None 1wxyzABCDE
50 return api_key 1FGHIJKLMNOPQRSTUVWXYZ012345
53class APIKeyQuery(APIKeyBase): 1abcd
54 """
55 API key authentication using a query parameter.
57 This defines the name of the query parameter that should be provided in the request
58 with the API key and integrates that into the OpenAPI documentation. It extracts
59 the key value sent in the query parameter automatically and provides it as the
60 dependency result. But it doesn't define how to send that API key to the client.
62 ## Usage
64 Create an instance object and use that object as the dependency in `Depends()`.
66 The dependency result will be a string containing the key value.
68 ## Example
70 ```python
71 from fastapi import Depends, FastAPI
72 from fastapi.security import APIKeyQuery
74 app = FastAPI()
76 query_scheme = APIKeyQuery(name="api_key")
79 @app.get("/items/")
80 async def read_items(api_key: str = Depends(query_scheme)):
81 return {"api_key": api_key}
82 ```
83 """
85 def __init__( 1abcd
86 self,
87 *,
88 name: Annotated[
89 str,
90 Doc("Query parameter name."),
91 ],
92 scheme_name: Annotated[
93 str | None,
94 Doc(
95 """
96 Security scheme name.
98 It will be included in the generated OpenAPI (e.g. visible at `/docs`).
99 """
100 ),
101 ] = None,
102 description: Annotated[
103 str | None,
104 Doc(
105 """
106 Security scheme description.
108 It will be included in the generated OpenAPI (e.g. visible at `/docs`).
109 """
110 ),
111 ] = None,
112 auto_error: Annotated[
113 bool,
114 Doc(
115 """
116 By default, if the query parameter is not provided, `APIKeyQuery` will
117 automatically cancel the request and send the client an error.
119 If `auto_error` is set to `False`, when the query parameter is not
120 available, instead of erroring out, the dependency result will be
121 `None`.
123 This is useful when you want to have optional authentication.
125 It is also useful when you want to have authentication that can be
126 provided in one of multiple optional ways (for example, in a query
127 parameter or in an HTTP Bearer token).
128 """
129 ),
130 ] = True,
131 ):
132 super().__init__( 1abcd
133 location=APIKeyIn.query,
134 name=name,
135 scheme_name=scheme_name,
136 description=description,
137 auto_error=auto_error,
138 )
140 async def __call__(self, request: Request) -> str | None: 1abcd
141 api_key = request.query_params.get(self.model.name) 1LiMjNyUoVpWB3u4v5E
142 return self.check_api_key(api_key) 1LiMjNyUoVpWB3u4v5E
145class APIKeyHeader(APIKeyBase): 1abcd
146 """
147 API key authentication using a header.
149 This defines the name of the header that should be provided in the request with
150 the API key and integrates that into the OpenAPI documentation. It extracts
151 the key value sent in the header automatically and provides it as the dependency
152 result. But it doesn't define how to send that key to the client.
154 ## Usage
156 Create an instance object and use that object as the dependency in `Depends()`.
158 The dependency result will be a string containing the key value.
160 ## Example
162 ```python
163 from fastapi import Depends, FastAPI
164 from fastapi.security import APIKeyHeader
166 app = FastAPI()
168 header_scheme = APIKeyHeader(name="x-key")
171 @app.get("/items/")
172 async def read_items(key: str = Depends(header_scheme)):
173 return {"key": key}
174 ```
175 """
177 def __init__( 1abcd
178 self,
179 *,
180 name: Annotated[str, Doc("Header name.")],
181 scheme_name: Annotated[
182 str | None,
183 Doc(
184 """
185 Security scheme name.
187 It will be included in the generated OpenAPI (e.g. visible at `/docs`).
188 """
189 ),
190 ] = None,
191 description: Annotated[
192 str | None,
193 Doc(
194 """
195 Security scheme description.
197 It will be included in the generated OpenAPI (e.g. visible at `/docs`).
198 """
199 ),
200 ] = None,
201 auto_error: Annotated[
202 bool,
203 Doc(
204 """
205 By default, if the header is not provided, `APIKeyHeader` will
206 automatically cancel the request and send the client an error.
208 If `auto_error` is set to `False`, when the header is not available,
209 instead of erroring out, the dependency result will be `None`.
211 This is useful when you want to have optional authentication.
213 It is also useful when you want to have authentication that can be
214 provided in one of multiple optional ways (for example, in a header or
215 in an HTTP Bearer token).
216 """
217 ),
218 ] = True,
219 ):
220 super().__init__( 1abcd
221 location=APIKeyIn.header,
222 name=name,
223 scheme_name=scheme_name,
224 description=description,
225 auto_error=auto_error,
226 )
228 async def __call__(self, request: Request) -> str | None: 1abcd
229 api_key = request.headers.get(self.model.name) 1IgJhKxRmSnTA0s1t2D
230 return self.check_api_key(api_key) 1IgJhKxRmSnTA0s1t2D
233class APIKeyCookie(APIKeyBase): 1abcd
234 """
235 API key authentication using a cookie.
237 This defines the name of the cookie that should be provided in the request with
238 the API key and integrates that into the OpenAPI documentation. It extracts
239 the key value sent in the cookie automatically and provides it as the dependency
240 result. But it doesn't define how to set that cookie.
242 ## Usage
244 Create an instance object and use that object as the dependency in `Depends()`.
246 The dependency result will be a string containing the key value.
248 ## Example
250 ```python
251 from fastapi import Depends, FastAPI
252 from fastapi.security import APIKeyCookie
254 app = FastAPI()
256 cookie_scheme = APIKeyCookie(name="session")
259 @app.get("/items/")
260 async def read_items(session: str = Depends(cookie_scheme)):
261 return {"session": session}
262 ```
263 """
265 def __init__( 1abcd
266 self,
267 *,
268 name: Annotated[str, Doc("Cookie name.")],
269 scheme_name: Annotated[
270 str | None,
271 Doc(
272 """
273 Security scheme name.
275 It will be included in the generated OpenAPI (e.g. visible at `/docs`).
276 """
277 ),
278 ] = None,
279 description: Annotated[
280 str | None,
281 Doc(
282 """
283 Security scheme description.
285 It will be included in the generated OpenAPI (e.g. visible at `/docs`).
286 """
287 ),
288 ] = None,
289 auto_error: Annotated[
290 bool,
291 Doc(
292 """
293 By default, if the cookie is not provided, `APIKeyCookie` will
294 automatically cancel the request and send the client an error.
296 If `auto_error` is set to `False`, when the cookie is not available,
297 instead of erroring out, the dependency result will be `None`.
299 This is useful when you want to have optional authentication.
301 It is also useful when you want to have authentication that can be
302 provided in one of multiple optional ways (for example, in a cookie or
303 in an HTTP Bearer token).
304 """
305 ),
306 ] = True,
307 ):
308 super().__init__( 1abcd
309 location=APIKeyIn.cookie,
310 name=name,
311 scheme_name=scheme_name,
312 description=description,
313 auto_error=auto_error,
314 )
316 async def __call__(self, request: Request) -> str | None: 1abcd
317 api_key = request.cookies.get(self.model.name) 1FeGfHwOkPlQzXqYrZC
318 return self.check_api_key(api_key) 1FeGfHwOkPlQzXqYrZC