Coverage for fastapi/security/oauth2.py: 100%
67 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 Any, Dict, List, Optional, Union, cast 1abcdefg
3from annotated_doc import Doc 1abcdefg
4from fastapi.exceptions import HTTPException 1abcdefg
5from fastapi.openapi.models import OAuth2 as OAuth2Model 1abcdefg
6from fastapi.openapi.models import OAuthFlows as OAuthFlowsModel 1abcdefg
7from fastapi.param_functions import Form 1abcdefg
8from fastapi.security.base import SecurityBase 1abcdefg
9from fastapi.security.utils import get_authorization_scheme_param 1abcdefg
10from starlette.requests import Request 1abcdefg
11from starlette.status import HTTP_401_UNAUTHORIZED 1abcdefg
13# TODO: import from typing when deprecating Python 3.9
14from typing_extensions import Annotated 1abcdefg
17class OAuth2PasswordRequestForm: 1abcdefg
18 """
19 This is a dependency class to collect the `username` and `password` as form data
20 for an OAuth2 password flow.
22 The OAuth2 specification dictates that for a password flow the data should be
23 collected using form data (instead of JSON) and that it should have the specific
24 fields `username` and `password`.
26 All the initialization parameters are extracted from the request.
28 Read more about it in the
29 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).
31 ## Example
33 ```python
34 from typing import Annotated
36 from fastapi import Depends, FastAPI
37 from fastapi.security import OAuth2PasswordRequestForm
39 app = FastAPI()
42 @app.post("/login")
43 def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]):
44 data = {}
45 data["scopes"] = []
46 for scope in form_data.scopes:
47 data["scopes"].append(scope)
48 if form_data.client_id:
49 data["client_id"] = form_data.client_id
50 if form_data.client_secret:
51 data["client_secret"] = form_data.client_secret
52 return data
53 ```
55 Note that for OAuth2 the scope `items:read` is a single scope in an opaque string.
56 You could have custom internal logic to separate it by colon characters (`:`) or
57 similar, and get the two parts `items` and `read`. Many applications do that to
58 group and organize permissions, you could do it as well in your application, just
59 know that that it is application specific, it's not part of the specification.
60 """
62 def __init__( 1abcdefg
63 self,
64 *,
65 grant_type: Annotated[
66 Union[str, None],
67 Form(pattern="^password$"),
68 Doc(
69 """
70 The OAuth2 spec says it is required and MUST be the fixed string
71 "password". Nevertheless, this dependency class is permissive and
72 allows not passing it. If you want to enforce it, use instead the
73 `OAuth2PasswordRequestFormStrict` dependency.
74 """
75 ),
76 ] = None,
77 username: Annotated[
78 str,
79 Form(),
80 Doc(
81 """
82 `username` string. The OAuth2 spec requires the exact field name
83 `username`.
84 """
85 ),
86 ],
87 password: Annotated[
88 str,
89 Form(json_schema_extra={"format": "password"}),
90 Doc(
91 """
92 `password` string. The OAuth2 spec requires the exact field name
93 `password`.
94 """
95 ),
96 ],
97 scope: Annotated[
98 str,
99 Form(),
100 Doc(
101 """
102 A single string with actually several scopes separated by spaces. Each
103 scope is also a string.
105 For example, a single string with:
107 ```python
108 "items:read items:write users:read profile openid"
109 ````
111 would represent the scopes:
113 * `items:read`
114 * `items:write`
115 * `users:read`
116 * `profile`
117 * `openid`
118 """
119 ),
120 ] = "",
121 client_id: Annotated[
122 Union[str, None],
123 Form(),
124 Doc(
125 """
126 If there's a `client_id`, it can be sent as part of the form fields.
127 But the OAuth2 specification recommends sending the `client_id` and
128 `client_secret` (if any) using HTTP Basic auth.
129 """
130 ),
131 ] = None,
132 client_secret: Annotated[
133 Union[str, None],
134 Form(json_schema_extra={"format": "password"}),
135 Doc(
136 """
137 If there's a `client_password` (and a `client_id`), they can be sent
138 as part of the form fields. But the OAuth2 specification recommends
139 sending the `client_id` and `client_secret` (if any) using HTTP Basic
140 auth.
141 """
142 ),
143 ] = None,
144 ):
145 self.grant_type = grant_type 2Q R S # $ % ' ( ) h i j k l T U V * + , - . / m n o p q W X Y : ; = ? @ [ r s t u v Z 0 1 ] ^ _ ` { | w x y z A 2 3 4 } ~ abbbcbdbB C D E F 5 6 7 ebfbgbhbibjbG H I J K 8 9 ! kblbmbnbobpbL M N O P
146 self.username = username 2Q R S # $ % ' ( ) h i j k l T U V * + , - . / m n o p q W X Y : ; = ? @ [ r s t u v Z 0 1 ] ^ _ ` { | w x y z A 2 3 4 } ~ abbbcbdbB C D E F 5 6 7 ebfbgbhbibjbG H I J K 8 9 ! kblbmbnbobpbL M N O P
147 self.password = password 2Q R S # $ % ' ( ) h i j k l T U V * + , - . / m n o p q W X Y : ; = ? @ [ r s t u v Z 0 1 ] ^ _ ` { | w x y z A 2 3 4 } ~ abbbcbdbB C D E F 5 6 7 ebfbgbhbibjbG H I J K 8 9 ! kblbmbnbobpbL M N O P
148 self.scopes = scope.split() 2Q R S # $ % ' ( ) h i j k l T U V * + , - . / m n o p q W X Y : ; = ? @ [ r s t u v Z 0 1 ] ^ _ ` { | w x y z A 2 3 4 } ~ abbbcbdbB C D E F 5 6 7 ebfbgbhbibjbG H I J K 8 9 ! kblbmbnbobpbL M N O P
149 self.client_id = client_id 2Q R S # $ % ' ( ) h i j k l T U V * + , - . / m n o p q W X Y : ; = ? @ [ r s t u v Z 0 1 ] ^ _ ` { | w x y z A 2 3 4 } ~ abbbcbdbB C D E F 5 6 7 ebfbgbhbibjbG H I J K 8 9 ! kblbmbnbobpbL M N O P
150 self.client_secret = client_secret 2Q R S # $ % ' ( ) h i j k l T U V * + , - . / m n o p q W X Y : ; = ? @ [ r s t u v Z 0 1 ] ^ _ ` { | w x y z A 2 3 4 } ~ abbbcbdbB C D E F 5 6 7 ebfbgbhbibjbG H I J K 8 9 ! kblbmbnbobpbL M N O P
153class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm): 1abcdefg
154 """
155 This is a dependency class to collect the `username` and `password` as form data
156 for an OAuth2 password flow.
158 The OAuth2 specification dictates that for a password flow the data should be
159 collected using form data (instead of JSON) and that it should have the specific
160 fields `username` and `password`.
162 All the initialization parameters are extracted from the request.
164 The only difference between `OAuth2PasswordRequestFormStrict` and
165 `OAuth2PasswordRequestForm` is that `OAuth2PasswordRequestFormStrict` requires the
166 client to send the form field `grant_type` with the value `"password"`, which
167 is required in the OAuth2 specification (it seems that for no particular reason),
168 while for `OAuth2PasswordRequestForm` `grant_type` is optional.
170 Read more about it in the
171 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).
173 ## Example
175 ```python
176 from typing import Annotated
178 from fastapi import Depends, FastAPI
179 from fastapi.security import OAuth2PasswordRequestForm
181 app = FastAPI()
184 @app.post("/login")
185 def login(form_data: Annotated[OAuth2PasswordRequestFormStrict, Depends()]):
186 data = {}
187 data["scopes"] = []
188 for scope in form_data.scopes:
189 data["scopes"].append(scope)
190 if form_data.client_id:
191 data["client_id"] = form_data.client_id
192 if form_data.client_secret:
193 data["client_secret"] = form_data.client_secret
194 return data
195 ```
197 Note that for OAuth2 the scope `items:read` is a single scope in an opaque string.
198 You could have custom internal logic to separate it by colon characters (`:`) or
199 similar, and get the two parts `items` and `read`. Many applications do that to
200 group and organize permissions, you could do it as well in your application, just
201 know that that it is application specific, it's not part of the specification.
204 grant_type: the OAuth2 spec says it is required and MUST be the fixed string "password".
205 This dependency is strict about it. If you want to be permissive, use instead the
206 OAuth2PasswordRequestForm dependency class.
207 username: username string. The OAuth2 spec requires the exact field name "username".
208 password: password string. The OAuth2 spec requires the exact field name "password".
209 scope: Optional string. Several scopes (each one a string) separated by spaces. E.g.
210 "items:read items:write users:read profile openid"
211 client_id: optional string. OAuth2 recommends sending the client_id and client_secret (if any)
212 using HTTP Basic auth, as: client_id:client_secret
213 client_secret: optional string. OAuth2 recommends sending the client_id and client_secret (if any)
214 using HTTP Basic auth, as: client_id:client_secret
215 """
217 def __init__( 1abcdefg
218 self,
219 grant_type: Annotated[
220 str,
221 Form(pattern="^password$"),
222 Doc(
223 """
224 The OAuth2 spec says it is required and MUST be the fixed string
225 "password". This dependency is strict about it. If you want to be
226 permissive, use instead the `OAuth2PasswordRequestForm` dependency
227 class.
228 """
229 ),
230 ],
231 username: Annotated[
232 str,
233 Form(),
234 Doc(
235 """
236 `username` string. The OAuth2 spec requires the exact field name
237 `username`.
238 """
239 ),
240 ],
241 password: Annotated[
242 str,
243 Form(),
244 Doc(
245 """
246 `password` string. The OAuth2 spec requires the exact field name
247 `password`.
248 """
249 ),
250 ],
251 scope: Annotated[
252 str,
253 Form(),
254 Doc(
255 """
256 A single string with actually several scopes separated by spaces. Each
257 scope is also a string.
259 For example, a single string with:
261 ```python
262 "items:read items:write users:read profile openid"
263 ````
265 would represent the scopes:
267 * `items:read`
268 * `items:write`
269 * `users:read`
270 * `profile`
271 * `openid`
272 """
273 ),
274 ] = "",
275 client_id: Annotated[
276 Union[str, None],
277 Form(),
278 Doc(
279 """
280 If there's a `client_id`, it can be sent as part of the form fields.
281 But the OAuth2 specification recommends sending the `client_id` and
282 `client_secret` (if any) using HTTP Basic auth.
283 """
284 ),
285 ] = None,
286 client_secret: Annotated[
287 Union[str, None],
288 Form(),
289 Doc(
290 """
291 If there's a `client_password` (and a `client_id`), they can be sent
292 as part of the form fields. But the OAuth2 specification recommends
293 sending the `client_id` and `client_secret` (if any) using HTTP Basic
294 auth.
295 """
296 ),
297 ] = None,
298 ):
299 super().__init__( 1QRSTUVWXYZ0123456789!
300 grant_type=grant_type,
301 username=username,
302 password=password,
303 scope=scope,
304 client_id=client_id,
305 client_secret=client_secret,
306 )
309class OAuth2(SecurityBase): 1abcdefg
310 """
311 This is the base class for OAuth2 authentication, an instance of it would be used
312 as a dependency. All other OAuth2 classes inherit from it and customize it for
313 each OAuth2 flow.
315 You normally would not create a new class inheriting from it but use one of the
316 existing subclasses, and maybe compose them if you want to support multiple flows.
318 Read more about it in the
319 [FastAPI docs for Security](https://fastapi.tiangolo.com/tutorial/security/).
320 """
322 def __init__( 1abcdefg
323 self,
324 *,
325 flows: Annotated[
326 Union[OAuthFlowsModel, Dict[str, Dict[str, Any]]],
327 Doc(
328 """
329 The dictionary of OAuth2 flows.
330 """
331 ),
332 ] = OAuthFlowsModel(),
333 scheme_name: Annotated[
334 Optional[str],
335 Doc(
336 """
337 Security scheme name.
339 It will be included in the generated OpenAPI (e.g. visible at `/docs`).
340 """
341 ),
342 ] = None,
343 description: Annotated[
344 Optional[str],
345 Doc(
346 """
347 Security scheme description.
349 It will be included in the generated OpenAPI (e.g. visible at `/docs`).
350 """
351 ),
352 ] = None,
353 auto_error: Annotated[
354 bool,
355 Doc(
356 """
357 By default, if no HTTP Authorization header is provided, required for
358 OAuth2 authentication, it will automatically cancel the request and
359 send the client an error.
361 If `auto_error` is set to `False`, when the HTTP Authorization header
362 is not available, instead of erroring out, the dependency result will
363 be `None`.
365 This is useful when you want to have optional authentication.
367 It is also useful when you want to have authentication that can be
368 provided in one of multiple optional ways (for example, with OAuth2
369 or in a cookie).
370 """
371 ),
372 ] = True,
373 ):
374 self.model = OAuth2Model( 1abcdefg
375 flows=cast(OAuthFlowsModel, flows), description=description
376 )
377 self.scheme_name = scheme_name or self.__class__.__name__ 1abcdefg
378 self.auto_error = auto_error 1abcdefg
380 def make_not_authenticated_error(self) -> HTTPException: 1abcdefg
381 """
382 The OAuth 2 specification doesn't define the challenge that should be used,
383 because a `Bearer` token is not really the only option to authenticate.
385 But declaring any other authentication challenge would be application-specific
386 as it's not defined in the specification.
388 For practical reasons, this method uses the `Bearer` challenge by default, as
389 it's probably the most common one.
391 If you are implementing an OAuth2 authentication scheme other than the provided
392 ones in FastAPI (based on bearer tokens), you might want to override this.
394 Ref: https://datatracker.ietf.org/doc/html/rfc6749
395 """
396 return HTTPException( 21cqbrbsbtbubvbwbxbybzbAb2cBbCbDbEbFbGbHbIbJbKbLb3cMbNbObPbQbRbSbTbUbVbWb4cXbYbZb0b1b2b3b4b5b6b7b5c8b9b!b#b$b%b'b(b)b*b+b6c,b-b.b/b:b;b=b?b@b[b]b7c^b_b`b{b|b}b~bacbcccdc
397 status_code=HTTP_401_UNAUTHORIZED,
398 detail="Not authenticated",
399 headers={"WWW-Authenticate": "Bearer"},
400 )
402 async def __call__(self, request: Request) -> Optional[str]: 1abcdefg
403 authorization = request.headers.get("Authorization") 2*d1c+d,d~c-d.dad/d:d2c;d=dbd?d@dcd[d]d3c^d_ddd`d{ded|d}d4c~daefdbecegddeee5cfegehdheieidjeke6clemejdneoekdpeqe7creseldteuemdve
404 if not authorization: 2*d1c+d,d~c-d.dad/d:d2c;d=dbd?d@dcd[d]d3c^d_ddd`d{ded|d}d4c~daefdbecegddeee5cfegehdheieidjeke6clemejdneoekdpeqe7creseldteuemdve
405 if self.auto_error: 21c~cad2cbdcd3cdded4cfdgd5chdid6cjdkd7cldmd
406 raise self.make_not_authenticated_error() 21c2c3c4c5c6c7c
407 else:
408 return None 2~cadbdcdddedfdgdhdidjdkdldmd
409 return authorization 2*d+d,d-d.d/d:d;d=d?d@d[d]d^d_d`d{d|d}d~daebecedeeefegeheiejekelemeneoepeqereseteueve
412class OAuth2PasswordBearer(OAuth2): 1abcdefg
413 """
414 OAuth2 flow for authentication using a bearer token obtained with a password.
415 An instance of it would be used as a dependency.
417 Read more about it in the
418 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).
419 """
421 def __init__( 1abcdefg
422 self,
423 tokenUrl: Annotated[
424 str,
425 Doc(
426 """
427 The URL to obtain the OAuth2 token. This would be the *path operation*
428 that has `OAuth2PasswordRequestForm` as a dependency.
429 """
430 ),
431 ],
432 scheme_name: Annotated[
433 Optional[str],
434 Doc(
435 """
436 Security scheme name.
438 It will be included in the generated OpenAPI (e.g. visible at `/docs`).
439 """
440 ),
441 ] = None,
442 scopes: Annotated[
443 Optional[Dict[str, str]],
444 Doc(
445 """
446 The OAuth2 scopes that would be required by the *path operations* that
447 use this dependency.
448 """
449 ),
450 ] = None,
451 description: Annotated[
452 Optional[str],
453 Doc(
454 """
455 Security scheme description.
457 It will be included in the generated OpenAPI (e.g. visible at `/docs`).
458 """
459 ),
460 ] = None,
461 auto_error: Annotated[
462 bool,
463 Doc(
464 """
465 By default, if no HTTP Authorization header is provided, required for
466 OAuth2 authentication, it will automatically cancel the request and
467 send the client an error.
469 If `auto_error` is set to `False`, when the HTTP Authorization header
470 is not available, instead of erroring out, the dependency result will
471 be `None`.
473 This is useful when you want to have optional authentication.
475 It is also useful when you want to have authentication that can be
476 provided in one of multiple optional ways (for example, with OAuth2
477 or in a cookie).
478 """
479 ),
480 ] = True,
481 refreshUrl: Annotated[
482 Optional[str],
483 Doc(
484 """
485 The URL to refresh the token and obtain a new one.
486 """
487 ),
488 ] = None,
489 ):
490 if not scopes: 1abcdefg
491 scopes = {} 1abcdefg
492 flows = OAuthFlowsModel( 1abcdefg
493 password=cast(
494 Any,
495 {
496 "tokenUrl": tokenUrl,
497 "refreshUrl": refreshUrl,
498 "scopes": scopes,
499 },
500 )
501 )
502 super().__init__( 1abcdefg
503 flows=flows,
504 scheme_name=scheme_name,
505 description=description,
506 auto_error=auto_error,
507 )
509 async def __call__(self, request: Request) -> Optional[str]: 1abcdefg
510 authorization = request.headers.get("Authorization") 2ecfcgc8c9cnd!c#codubvbpdqdrdwbxbsdhcybzbh i Abj k l icjckclcmcnc$c%ctd'c(cudFbGbvdwdxdHbIbydocJbKbm n Lbo p q pcqcrcsctcuc)c*czd+c,cAdQbRbBdCdDdSbTbEdvcUbVbr s Wbt u v wcxcyczcAcBc-c.cFd/c:cGd1b2bHdIdJd3b4bKdCc5b6bw x 7by z A DcEcFcGcHcIc;c=cLd?c@cMd$b%bNdOdPd'b(bQdJc)b*bB C +bD E F KcLcMcNcOcPc[c]cRd^c_cSd:b;bTdUdVd=b?bWdQc@b[bG H ]bI J K RcScTcUcVcWc`c{cXd|c}cYd|b}bZd0d1d~bac2dXcbcccL M dcN O P YcZc0c
511 scheme, param = get_authorization_scheme_param(authorization) 2ecfcgc8c9cnd!c#codubvbpdqdrdwbxbsdhcybzbh i Abj k l icjckclcmcnc$c%ctd'c(cudFbGbvdwdxdHbIbydocJbKbm n Lbo p q pcqcrcsctcuc)c*czd+c,cAdQbRbBdCdDdSbTbEdvcUbVbr s Wbt u v wcxcyczcAcBc-c.cFd/c:cGd1b2bHdIdJd3b4bKdCc5b6bw x 7by z A DcEcFcGcHcIc;c=cLd?c@cMd$b%bNdOdPd'b(bQdJc)b*bB C +bD E F KcLcMcNcOcPc[c]cRd^c_cSd:b;bTdUdVd=b?bWdQc@b[bG H ]bI J K RcScTcUcVcWc`c{cXd|c}cYd|b}bZd0d1d~bac2dXcbcccL M dcN O P YcZc0c
512 if not authorization or scheme.lower() != "bearer": 2ecfcgc8c9cnd!c#codubvbpdqdrdwbxbsdhcybzbh i Abj k l icjckclcmcnc$c%ctd'c(cudFbGbvdwdxdHbIbydocJbKbm n Lbo p q pcqcrcsctcuc)c*czd+c,cAdQbRbBdCdDdSbTbEdvcUbVbr s Wbt u v wcxcyczcAcBc-c.cFd/c:cGd1b2bHdIdJd3b4bKdCc5b6bw x 7by z A DcEcFcGcHcIc;c=cLd?c@cMd$b%bNdOdPd'b(bQdJc)b*bB C +bD E F KcLcMcNcOcPc[c]cRd^c_cSd:b;bTdUdVd=b?bWdQc@b[bG H ]bI J K RcScTcUcVcWc`c{cXd|c}cYd|b}bZd0d1d~bac2dXcbcccL M dcN O P YcZc0c
513 if self.auto_error: 28c9c!c#cubvbwbxbybzbAb$c%c'c(cFbGbHbIbJbKbLb)c*c+c,cQbRbSbTbUbVbWb-c.c/c:c1b2b3b4b5b6b7b;c=c?c@c$b%b'b(b)b*b+b[c]c^c_c:b;b=b?b@b[b]b`c{c|c}c|b}b~bacbcccdc
514 raise self.make_not_authenticated_error() 2ubvbwbxbybzbAbFbGbHbIbJbKbLbQbRbSbTbUbVbWb1b2b3b4b5b6b7b$b%b'b(b)b*b+b:b;b=b?b@b[b]b|b}b~bacbcccdc
515 else:
516 return None 28c9c!c#c$c%c'c(c)c*c+c,c-c.c/c:c;c=c?c@c[c]c^c_c`c{c|c}c
517 return param 2ecfcgcndodpdqdrdsdhch i j k l icjckclcmcnctdudvdwdxdydocm n o p q pcqcrcsctcuczdAdBdCdDdEdvcr s t u v wcxcyczcAcBcFdGdHdIdJdKdCcw x y z A DcEcFcGcHcIcLdMdNdOdPdQdJcB C D E F KcLcMcNcOcPcRdSdTdUdVdWdQcG H I J K RcScTcUcVcWcXdYdZd0d1d2dXcL M N O P YcZc0c
520class OAuth2AuthorizationCodeBearer(OAuth2): 1abcdefg
521 """
522 OAuth2 flow for authentication using a bearer token obtained with an OAuth2 code
523 flow. An instance of it would be used as a dependency.
524 """
526 def __init__( 1abcdefg
527 self,
528 authorizationUrl: str,
529 tokenUrl: Annotated[
530 str,
531 Doc(
532 """
533 The URL to obtain the OAuth2 token.
534 """
535 ),
536 ],
537 refreshUrl: Annotated[
538 Optional[str],
539 Doc(
540 """
541 The URL to refresh the token and obtain a new one.
542 """
543 ),
544 ] = None,
545 scheme_name: Annotated[
546 Optional[str],
547 Doc(
548 """
549 Security scheme name.
551 It will be included in the generated OpenAPI (e.g. visible at `/docs`).
552 """
553 ),
554 ] = None,
555 scopes: Annotated[
556 Optional[Dict[str, str]],
557 Doc(
558 """
559 The OAuth2 scopes that would be required by the *path operations* that
560 use this dependency.
561 """
562 ),
563 ] = None,
564 description: Annotated[
565 Optional[str],
566 Doc(
567 """
568 Security scheme description.
570 It will be included in the generated OpenAPI (e.g. visible at `/docs`).
571 """
572 ),
573 ] = None,
574 auto_error: Annotated[
575 bool,
576 Doc(
577 """
578 By default, if no HTTP Authorization header is provided, required for
579 OAuth2 authentication, it will automatically cancel the request and
580 send the client an error.
582 If `auto_error` is set to `False`, when the HTTP Authorization header
583 is not available, instead of erroring out, the dependency result will
584 be `None`.
586 This is useful when you want to have optional authentication.
588 It is also useful when you want to have authentication that can be
589 provided in one of multiple optional ways (for example, with OAuth2
590 or in a cookie).
591 """
592 ),
593 ] = True,
594 ):
595 if not scopes: 1abcdefg
596 scopes = {} 1abcdefg
597 flows = OAuthFlowsModel( 1abcdefg
598 authorizationCode=cast(
599 Any,
600 {
601 "authorizationUrl": authorizationUrl,
602 "tokenUrl": tokenUrl,
603 "refreshUrl": refreshUrl,
604 "scopes": scopes,
605 },
606 )
607 )
608 super().__init__( 1abcdefg
609 flows=flows,
610 scheme_name=scheme_name,
611 description=description,
612 auto_error=auto_error,
613 )
615 async def __call__(self, request: Request) -> Optional[str]: 1abcdefg
616 authorization = request.headers.get("Authorization") 2qbrb3dsbtb4dBbCb5dDbEb6dMbNb7dObPb8dXbYb9dZb0b!d8b9b#d!b#b$d,b-b%d.b/b'd^b_b(d`b{b)d
617 scheme, param = get_authorization_scheme_param(authorization) 2qbrb3dsbtb4dBbCb5dDbEb6dMbNb7dObPb8dXbYb9dZb0b!d8b9b#d!b#b$d,b-b%d.b/b'd^b_b(d`b{b)d
618 if not authorization or scheme.lower() != "bearer": 2qbrb3dsbtb4dBbCb5dDbEb6dMbNb7dObPb8dXbYb9dZb0b!d8b9b#d!b#b$d,b-b%d.b/b'd^b_b(d`b{b)d
619 if self.auto_error: 2qbrbsbtbBbCbDbEbMbNbObPbXbYbZb0b8b9b!b#b,b-b.b/b^b_b`b{b
620 raise self.make_not_authenticated_error() 2qbrbsbtbBbCbDbEbMbNbObPbXbYbZb0b8b9b!b#b,b-b.b/b^b_b`b{b
621 else:
622 return None # pragma: nocover
623 return param 23d4d5d6d7d8d9d!d#d$d%d'd(d)d
626class SecurityScopes: 1abcdefg
627 """
628 This is a special class that you can define in a parameter in a dependency to
629 obtain the OAuth2 scopes required by all the dependencies in the same chain.
631 This way, multiple dependencies can have different scopes, even when used in the
632 same *path operation*. And with this, you can access all the scopes required in
633 all those dependencies in a single place.
635 Read more about it in the
636 [FastAPI docs for OAuth2 scopes](https://fastapi.tiangolo.com/advanced/security/oauth2-scopes/).
637 """
639 def __init__( 1abcdefg
640 self,
641 scopes: Annotated[
642 Optional[List[str]],
643 Doc(
644 """
645 This will be filled by FastAPI.
646 """
647 ),
648 ] = None,
649 ):
650 self.scopes: Annotated[ 2ecfcgcwexeyezeAehch i j k l icjckclcmcncBeCeDeEeFeocm n o p q pcqcrcsctcucGeHeIeJeKevcr s t u v wcxcyczcAcBcLeMeNeOePeCcw x y z A DcEcFcGcHcIcQeReSeTeUeJcB C D E F KcLcMcNcOcPcVeWeXeYeZeQcG H I J K RcScTcUcVcWc0e1e2e3e4eXcL M N O P YcZc0c
651 List[str],
652 Doc(
653 """
654 The list of all the scopes required by dependencies.
655 """
656 ),
657 ] = scopes or []
658 self.scope_str: Annotated[ 2ecfcgcwexeyezeAehch i j k l icjckclcmcncBeCeDeEeFeocm n o p q pcqcrcsctcucGeHeIeJeKevcr s t u v wcxcyczcAcBcLeMeNeOePeCcw x y z A DcEcFcGcHcIcQeReSeTeUeJcB C D E F KcLcMcNcOcPcVeWeXeYeZeQcG H I J K RcScTcUcVcWc0e1e2e3e4eXcL M N O P YcZc0c
659 str,
660 Doc(
661 """
662 All the scopes required by all the dependencies in a single string
663 separated by spaces, as defined in the OAuth2 specification.
664 """
665 ),
666 ] = " ".join(self.scopes)