Coverage for fastapi/security/api_key.py: 100%
39 statements
« prev ^ index » next coverage.py v7.6.1, created at 2025-12-04 08:29 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2025-12-04 08:29 +0000
1from typing import Optional, Union 1abcdefg
3from annotated_doc import Doc 1abcdefg
4from fastapi.openapi.models import APIKey, APIKeyIn 1abcdefg
5from fastapi.security.base import SecurityBase 1abcdefg
6from starlette.exceptions import HTTPException 1abcdefg
7from starlette.requests import Request 1abcdefg
8from starlette.status import HTTP_401_UNAUTHORIZED 1abcdefg
9from typing_extensions import Annotated 1abcdefg
12class APIKeyBase(SecurityBase): 1abcdefg
13 def __init__( 1abcdefg
14 self,
15 location: APIKeyIn,
16 name: str,
17 description: Union[str, None],
18 scheme_name: Union[str, None],
19 auto_error: bool,
20 ):
21 self.auto_error = auto_error 1abcdefg
23 self.model: APIKey = APIKey( 1abcdefg
24 **{"in": location},
25 name=name,
26 description=description,
27 )
28 self.scheme_name = scheme_name or self.__class__.__name__ 1abcdefg
30 def make_not_authenticated_error(self) -> HTTPException: 1abcdefg
31 """
32 The WWW-Authenticate header is not standardized for API Key authentication but
33 the HTTP specification requires that an error of 401 "Unauthorized" must
34 include a WWW-Authenticate header.
36 Ref: https://datatracker.ietf.org/doc/html/rfc9110#name-401-unauthorized
38 For this, this method sends a custom challenge `APIKey`.
39 """
40 return HTTPException( 1hijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVW
41 status_code=HTTP_401_UNAUTHORIZED,
42 detail="Not authenticated",
43 headers={"WWW-Authenticate": "APIKey"},
44 )
46 def check_api_key(self, api_key: Optional[str]) -> Optional[str]: 1abcdefg
47 if not api_key: 2+ h , i - X . j / k : Y ; l = m ? Z @ n [ o ] 0 ^ p _ q ` 1 { r | s } 2 ~ t abu bb3 cbv dbw eb4 fbx gby hb5 ibz jbA kb6 lbB mbC nb7 obD pbE qb8 rbF sbG tb9 ubH vbI wb! xbJ ybK zb# AbL BbM Cb$ DbN EbO Fb% GbP HbQ Ib' JbR KbS Lb( MbT NbU Ob) PbV QbW Rb*
48 if self.auto_error: 1hiXjkYlmZno0pq1rs2tu3vw4xy5zA6BC7DE8FG9HI!JK#LM$NO%PQ'RS(TU)VW*
49 raise self.make_not_authenticated_error() 1hijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVW
50 return None 1XYZ0123456789!#$%'()*
51 return api_key 2+ , - . / : ; = ? @ [ ] ^ _ ` { | } ~ abbbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRb
54class APIKeyQuery(APIKeyBase): 1abcdefg
55 """
56 API key authentication using a query parameter.
58 This defines the name of the query parameter that should be provided in the request
59 with the API key and integrates that into the OpenAPI documentation. It extracts
60 the key value sent in the query parameter automatically and provides it as the
61 dependency result. But it doesn't define how to send that API key to the client.
63 ## Usage
65 Create an instance object and use that object as the dependency in `Depends()`.
67 The dependency result will be a string containing the key value.
69 ## Example
71 ```python
72 from fastapi import Depends, FastAPI
73 from fastapi.security import APIKeyQuery
75 app = FastAPI()
77 query_scheme = APIKeyQuery(name="api_key")
80 @app.get("/items/")
81 async def read_items(api_key: str = Depends(query_scheme)):
82 return {"api_key": api_key}
83 ```
84 """
86 def __init__( 1abcdefg
87 self,
88 *,
89 name: Annotated[
90 str,
91 Doc("Query parameter name."),
92 ],
93 scheme_name: Annotated[
94 Optional[str],
95 Doc(
96 """
97 Security scheme name.
99 It will be included in the generated OpenAPI (e.g. visible at `/docs`).
100 """
101 ),
102 ] = None,
103 description: Annotated[
104 Optional[str],
105 Doc(
106 """
107 Security scheme description.
109 It will be included in the generated OpenAPI (e.g. visible at `/docs`).
110 """
111 ),
112 ] = None,
113 auto_error: Annotated[
114 bool,
115 Doc(
116 """
117 By default, if the query parameter is not provided, `APIKeyQuery` will
118 automatically cancel the request and send the client an error.
120 If `auto_error` is set to `False`, when the query parameter is not
121 available, instead of erroring out, the dependency result will be
122 `None`.
124 This is useful when you want to have optional authentication.
126 It is also useful when you want to have authentication that can be
127 provided in one of multiple optional ways (for example, in a query
128 parameter or in an HTTP Bearer token).
129 """
130 ),
131 ] = True,
132 ):
133 super().__init__( 1abcdefg
134 location=APIKeyIn.query,
135 name=name,
136 scheme_name=scheme_name,
137 description=description,
138 auto_error=auto_error,
139 )
141 async def __call__(self, request: Request) -> Optional[str]: 1abcdefg
142 api_key = request.query_params.get(self.model.name) 2; l = m ? Z { r | s } 2 fbx gby hb5 obD pbE qb8 xbJ ybK zb# GbP HbQ Ib' PbV QbW Rb*
143 return self.check_api_key(api_key) 2; l = m ? Z { r | s } 2 fbx gby hb5 obD pbE qb8 xbJ ybK zb# GbP HbQ Ib' PbV QbW Rb*
146class APIKeyHeader(APIKeyBase): 1abcdefg
147 """
148 API key authentication using a header.
150 This defines the name of the header that should be provided in the request with
151 the API key and integrates that into the OpenAPI documentation. It extracts
152 the key value sent in the header automatically and provides it as the dependency
153 result. But it doesn't define how to send that key to the client.
155 ## Usage
157 Create an instance object and use that object as the dependency in `Depends()`.
159 The dependency result will be a string containing the key value.
161 ## Example
163 ```python
164 from fastapi import Depends, FastAPI
165 from fastapi.security import APIKeyHeader
167 app = FastAPI()
169 header_scheme = APIKeyHeader(name="x-key")
172 @app.get("/items/")
173 async def read_items(key: str = Depends(header_scheme)):
174 return {"key": key}
175 ```
176 """
178 def __init__( 1abcdefg
179 self,
180 *,
181 name: Annotated[str, Doc("Header name.")],
182 scheme_name: Annotated[
183 Optional[str],
184 Doc(
185 """
186 Security scheme name.
188 It will be included in the generated OpenAPI (e.g. visible at `/docs`).
189 """
190 ),
191 ] = None,
192 description: Annotated[
193 Optional[str],
194 Doc(
195 """
196 Security scheme description.
198 It will be included in the generated OpenAPI (e.g. visible at `/docs`).
199 """
200 ),
201 ] = None,
202 auto_error: Annotated[
203 bool,
204 Doc(
205 """
206 By default, if the header is not provided, `APIKeyHeader` will
207 automatically cancel the request and send the client an error.
209 If `auto_error` is set to `False`, when the header is not available,
210 instead of erroring out, the dependency result will be `None`.
212 This is useful when you want to have optional authentication.
214 It is also useful when you want to have authentication that can be
215 provided in one of multiple optional ways (for example, in a header or
216 in an HTTP Bearer token).
217 """
218 ),
219 ] = True,
220 ):
221 super().__init__( 1abcdefg
222 location=APIKeyIn.header,
223 name=name,
224 scheme_name=scheme_name,
225 description=description,
226 auto_error=auto_error,
227 )
229 async def __call__(self, request: Request) -> Optional[str]: 1abcdefg
230 api_key = request.headers.get(self.model.name) 2. j / k : Y ^ p _ q ` 1 cbv dbw eb4 lbB mbC nb7 ubH vbI wb! DbN EbO Fb% MbT NbU Ob)
231 return self.check_api_key(api_key) 2. j / k : Y ^ p _ q ` 1 cbv dbw eb4 lbB mbC nb7 ubH vbI wb! DbN EbO Fb% MbT NbU Ob)
234class APIKeyCookie(APIKeyBase): 1abcdefg
235 """
236 API key authentication using a cookie.
238 This defines the name of the cookie that should be provided in the request with
239 the API key and integrates that into the OpenAPI documentation. It extracts
240 the key value sent in the cookie automatically and provides it as the dependency
241 result. But it doesn't define how to set that cookie.
243 ## Usage
245 Create an instance object and use that object as the dependency in `Depends()`.
247 The dependency result will be a string containing the key value.
249 ## Example
251 ```python
252 from fastapi import Depends, FastAPI
253 from fastapi.security import APIKeyCookie
255 app = FastAPI()
257 cookie_scheme = APIKeyCookie(name="session")
260 @app.get("/items/")
261 async def read_items(session: str = Depends(cookie_scheme)):
262 return {"session": session}
263 ```
264 """
266 def __init__( 1abcdefg
267 self,
268 *,
269 name: Annotated[str, Doc("Cookie name.")],
270 scheme_name: Annotated[
271 Optional[str],
272 Doc(
273 """
274 Security scheme name.
276 It will be included in the generated OpenAPI (e.g. visible at `/docs`).
277 """
278 ),
279 ] = None,
280 description: Annotated[
281 Optional[str],
282 Doc(
283 """
284 Security scheme description.
286 It will be included in the generated OpenAPI (e.g. visible at `/docs`).
287 """
288 ),
289 ] = None,
290 auto_error: Annotated[
291 bool,
292 Doc(
293 """
294 By default, if the cookie is not provided, `APIKeyCookie` will
295 automatically cancel the request and send the client an error.
297 If `auto_error` is set to `False`, when the cookie is not available,
298 instead of erroring out, the dependency result will be `None`.
300 This is useful when you want to have optional authentication.
302 It is also useful when you want to have authentication that can be
303 provided in one of multiple optional ways (for example, in a cookie or
304 in an HTTP Bearer token).
305 """
306 ),
307 ] = True,
308 ):
309 super().__init__( 1abcdefg
310 location=APIKeyIn.cookie,
311 name=name,
312 scheme_name=scheme_name,
313 description=description,
314 auto_error=auto_error,
315 )
317 async def __call__(self, request: Request) -> Optional[str]: 1abcdefg
318 api_key = request.cookies.get(self.model.name) 2+ h , i - X @ n [ o ] 0 ~ t abu bb3 ibz jbA kb6 rbF sbG tb9 AbL BbM Cb$ JbR KbS Lb(
319 return self.check_api_key(api_key) 2+ h , i - X @ n [ o ] 0 ~ t abu bb3 ibz jbA kb6 rbF sbG tb9 AbL BbM Cb$ JbR KbS Lb(