Ensure functions have docstrings for documentation
def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]):
1from typing import Annotated, Any, cast23from annotated_doc import Doc4from fastapi.exceptions import HTTPException5from fastapi.openapi.models import OAuth2 as OAuth2Model6from fastapi.openapi.models import OAuthFlows as OAuthFlowsModel7from fastapi.param_functions import Form8from fastapi.security.base import SecurityBase9from fastapi.security.utils import get_authorization_scheme_param10from starlette.requests import Request11from starlette.status import HTTP_401_UNAUTHORIZED121314class OAuth2PasswordRequestForm:15 """16 This is a dependency class to collect the `username` and `password` as form data17 for an OAuth2 password flow.1819 The OAuth2 specification dictates that for a password flow the data should be20 collected using form data (instead of JSON) and that it should have the specific21 fields `username` and `password`.2223 All the initialization parameters are extracted from the request.2425 Read more about it in the26 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).2728 ## Example2930 ```python31 from typing import Annotated3233 from fastapi import Depends, FastAPI34 from fastapi.security import OAuth2PasswordRequestForm3536 app = FastAPI()373839 @app.post("/login")40 def login(form_data: Annotated[OAuth2PasswordRequestForm, Depends()]):41 data = {}42 data["scopes"] = []43 for scope in form_data.scopes:44 data["scopes"].append(scope)45 if form_data.client_id:46 data["client_id"] = form_data.client_id47 if form_data.client_secret:48 data["client_secret"] = form_data.client_secret49 return data50 ```5152 Note that for OAuth2 the scope `items:read` is a single scope in an opaque string.53 You could have custom internal logic to separate it by colon characters (`:`) or54 similar, and get the two parts `items` and `read`. Many applications do that to55 group and organize permissions, you could do it as well in your application, just56 know that it is application specific, it's not part of the specification.57 """5859 def __init__(60 self,61 *,62 grant_type: Annotated[63 str | None,64 Form(pattern="^password$"),65 Doc(66 """67 The OAuth2 spec says it is required and MUST be the fixed string68 "password". Nevertheless, this dependency class is permissive and69 allows not passing it. If you want to enforce it, use instead the70 `OAuth2PasswordRequestFormStrict` dependency.7172 Read more about it in the73 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).74 """75 ),76 ] = None,77 username: Annotated[78 str,79 Form(),80 Doc(81 """82 `username` string. The OAuth2 spec requires the exact field name83 `username`.8485 Read more about it in the86 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).87 """88 ),89 ],90 password: Annotated[91 str,92 Form(json_schema_extra={"format": "password"}),93 Doc(94 """95 `password` string. The OAuth2 spec requires the exact field name96 `password`.9798 Read more about it in the99 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).100 """101 ),102 ],103 scope: Annotated[104 str,105 Form(),106 Doc(107 """108 A single string with actually several scopes separated by spaces. Each109 scope is also a string.110111 For example, a single string with:112113 ```python114 "items:read items:write users:read profile openid"115 ````116117 would represent the scopes:118119 * `items:read`120 * `items:write`121 * `users:read`122 * `profile`123 * `openid`124125 Read more about it in the126 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).127 """128 ),129 ] = "",130 client_id: Annotated[131 str | None,132 Form(),133 Doc(134 """135 If there's a `client_id`, it can be sent as part of the form fields.136 But the OAuth2 specification recommends sending the `client_id` and137 `client_secret` (if any) using HTTP Basic auth.138 """139 ),140 ] = None,141 client_secret: Annotated[142 str | None,143 Form(json_schema_extra={"format": "password"}),144 Doc(145 """146 If there's a `client_secret` (and a `client_id`), they can be sent147 as part of the form fields. But the OAuth2 specification recommends148 sending the `client_id` and `client_secret` (if any) using HTTP Basic149 auth.150 """151 ),152 ] = None,153 ):154 self.grant_type = grant_type155 self.username = username156 self.password = password157 self.scopes = scope.split()158 self.client_id = client_id159 self.client_secret = client_secret160161162class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm):163 """164 This is a dependency class to collect the `username` and `password` as form data165 for an OAuth2 password flow.166167 The OAuth2 specification dictates that for a password flow the data should be168 collected using form data (instead of JSON) and that it should have the specific169 fields `username` and `password`.170171 All the initialization parameters are extracted from the request.172173 The only difference between `OAuth2PasswordRequestFormStrict` and174 `OAuth2PasswordRequestForm` is that `OAuth2PasswordRequestFormStrict` requires the175 client to send the form field `grant_type` with the value `"password"`, which176 is required in the OAuth2 specification (it seems that for no particular reason),177 while for `OAuth2PasswordRequestForm` `grant_type` is optional.178179 Read more about it in the180 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).181182 ## Example183184 ```python185 from typing import Annotated186187 from fastapi import Depends, FastAPI188 from fastapi.security import OAuth2PasswordRequestForm189190 app = FastAPI()191192193 @app.post("/login")194 def login(form_data: Annotated[OAuth2PasswordRequestFormStrict, Depends()]):195 data = {}196 data["scopes"] = []197 for scope in form_data.scopes:198 data["scopes"].append(scope)199 if form_data.client_id:200 data["client_id"] = form_data.client_id201 if form_data.client_secret:202 data["client_secret"] = form_data.client_secret203 return data204 ```205206 Note that for OAuth2 the scope `items:read` is a single scope in an opaque string.207 You could have custom internal logic to separate it by colon characters (`:`) or208 similar, and get the two parts `items` and `read`. Many applications do that to209 group and organize permissions, you could do it as well in your application, just210 know that it is application specific, it's not part of the specification.211212213 grant_type: the OAuth2 spec says it is required and MUST be the fixed string "password".214 This dependency is strict about it. If you want to be permissive, use instead the215 OAuth2PasswordRequestForm dependency class.216 username: username string. The OAuth2 spec requires the exact field name "username".217 password: password string. The OAuth2 spec requires the exact field name "password".218 scope: Optional string. Several scopes (each one a string) separated by spaces. E.g.219 "items:read items:write users:read profile openid"220 client_id: optional string. OAuth2 recommends sending the client_id and client_secret (if any)221 using HTTP Basic auth, as: client_id:client_secret222 client_secret: optional string. OAuth2 recommends sending the client_id and client_secret (if any)223 using HTTP Basic auth, as: client_id:client_secret224 """225226 def __init__(227 self,228 grant_type: Annotated[229 str,230 Form(pattern="^password$"),231 Doc(232 """233 The OAuth2 spec says it is required and MUST be the fixed string234 "password". This dependency is strict about it. If you want to be235 permissive, use instead the `OAuth2PasswordRequestForm` dependency236 class.237238 Read more about it in the239 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).240 """241 ),242 ],243 username: Annotated[244 str,245 Form(),246 Doc(247 """248 `username` string. The OAuth2 spec requires the exact field name249 `username`.250251 Read more about it in the252 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).253 """254 ),255 ],256 password: Annotated[257 str,258 Form(),259 Doc(260 """261 `password` string. The OAuth2 spec requires the exact field name262 `password`.263264 Read more about it in the265 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).266 """267 ),268 ],269 scope: Annotated[270 str,271 Form(),272 Doc(273 """274 A single string with actually several scopes separated by spaces. Each275 scope is also a string.276277 For example, a single string with:278279 ```python280 "items:read items:write users:read profile openid"281 ````282283 would represent the scopes:284285 * `items:read`286 * `items:write`287 * `users:read`288 * `profile`289 * `openid`290291 Read more about it in the292 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).293 """294 ),295 ] = "",296 client_id: Annotated[297 str | None,298 Form(),299 Doc(300 """301 If there's a `client_id`, it can be sent as part of the form fields.302 But the OAuth2 specification recommends sending the `client_id` and303 `client_secret` (if any) using HTTP Basic auth.304 """305 ),306 ] = None,307 client_secret: Annotated[308 str | None,309 Form(),310 Doc(311 """312 If there's a `client_secret` (and a `client_id`), they can be sent313 as part of the form fields. But the OAuth2 specification recommends314 sending the `client_id` and `client_secret` (if any) using HTTP Basic315 auth.316 """317 ),318 ] = None,319 ):320 super().__init__(321 grant_type=grant_type,322 username=username,323 password=password,324 scope=scope,325 client_id=client_id,326 client_secret=client_secret,327 )328329330class OAuth2(SecurityBase):331 """332 This is the base class for OAuth2 authentication, an instance of it would be used333 as a dependency. All other OAuth2 classes inherit from it and customize it for334 each OAuth2 flow.335336 You normally would not create a new class inheriting from it but use one of the337 existing subclasses, and maybe compose them if you want to support multiple flows.338339 Read more about it in the340 [FastAPI docs for Security](https://fastapi.tiangolo.com/tutorial/security/).341 """342343 def __init__(344 self,345 *,346 flows: Annotated[347 OAuthFlowsModel | dict[str, dict[str, Any]],348 Doc(349 """350 The dictionary of OAuth2 flows.351 """352 ),353 ] = OAuthFlowsModel(),354 scheme_name: Annotated[355 str | None,356 Doc(357 """358 Security scheme name.359360 It will be included in the generated OpenAPI (e.g. visible at `/docs`).361 """362 ),363 ] = None,364 description: Annotated[365 str | None,366 Doc(367 """368 Security scheme description.369370 It will be included in the generated OpenAPI (e.g. visible at `/docs`).371 """372 ),373 ] = None,374 auto_error: Annotated[375 bool,376 Doc(377 """378 By default, if no HTTP Authorization header is provided, required for379 OAuth2 authentication, it will automatically cancel the request and380 send the client an error.381382 If `auto_error` is set to `False`, when the HTTP Authorization header383 is not available, instead of erroring out, the dependency result will384 be `None`.385386 This is useful when you want to have optional authentication.387388 It is also useful when you want to have authentication that can be389 provided in one of multiple optional ways (for example, with OAuth2390 or in a cookie).391 """392 ),393 ] = True,394 ):395 self.model = OAuth2Model(396 flows=cast(OAuthFlowsModel, flows), description=description397 )398 self.scheme_name = scheme_name or self.__class__.__name__399 self.auto_error = auto_error400401 def make_not_authenticated_error(self) -> HTTPException:402 """403 The OAuth 2 specification doesn't define the challenge that should be used,404 because a `Bearer` token is not really the only option to authenticate.405406 But declaring any other authentication challenge would be application-specific407 as it's not defined in the specification.408409 For practical reasons, this method uses the `Bearer` challenge by default, as410 it's probably the most common one.411412 If you are implementing an OAuth2 authentication scheme other than the provided413 ones in FastAPI (based on bearer tokens), you might want to override this.414415 Ref: https://datatracker.ietf.org/doc/html/rfc6749416 """417 return HTTPException(418 status_code=HTTP_401_UNAUTHORIZED,419 detail="Not authenticated",420 headers={"WWW-Authenticate": "Bearer"},421 )422423 async def __call__(self, request: Request) -> str | None:424 authorization = request.headers.get("Authorization")425 if not authorization:426 if self.auto_error:427 raise self.make_not_authenticated_error()428 else:429 return None430 return authorization431432433class OAuth2PasswordBearer(OAuth2):434 """435 OAuth2 flow for authentication using a bearer token obtained with a password.436 An instance of it would be used as a dependency.437438 Read more about it in the439 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).440 """441442 def __init__(443 self,444 tokenUrl: Annotated[445 str,446 Doc(447 """448 The URL to obtain the OAuth2 token. This would be the *path operation*449 that has `OAuth2PasswordRequestForm` as a dependency.450451 Read more about it in the452 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).453 """454 ),455 ],456 scheme_name: Annotated[457 str | None,458 Doc(459 """460 Security scheme name.461462 It will be included in the generated OpenAPI (e.g. visible at `/docs`).463 """464 ),465 ] = None,466 scopes: Annotated[467 dict[str, str] | None,468 Doc(469 """470 The OAuth2 scopes that would be required by the *path operations* that471 use this dependency.472473 Read more about it in the474 [FastAPI docs for Simple OAuth2 with Password and Bearer](https://fastapi.tiangolo.com/tutorial/security/simple-oauth2/).475 """476 ),477 ] = None,478 description: Annotated[479 str | None,480 Doc(481 """482 Security scheme description.483484 It will be included in the generated OpenAPI (e.g. visible at `/docs`).485 """486 ),487 ] = None,488 auto_error: Annotated[489 bool,490 Doc(491 """492 By default, if no HTTP Authorization header is provided, required for493 OAuth2 authentication, it will automatically cancel the request and494 send the client an error.495496 If `auto_error` is set to `False`, when the HTTP Authorization header497 is not available, instead of erroring out, the dependency result will498 be `None`.499500 This is useful when you want to have optional authentication.501502 It is also useful when you want to have authentication that can be503 provided in one of multiple optional ways (for example, with OAuth2504 or in a cookie).505 """506 ),507 ] = True,508 refreshUrl: Annotated[509 str | None,510 Doc(511 """512 The URL to refresh the token and obtain a new one.513 """514 ),515 ] = None,516 ):517 if not scopes:518 scopes = {}519 flows = OAuthFlowsModel(520 password=cast(521 Any,522 {523 "tokenUrl": tokenUrl,524 "refreshUrl": refreshUrl,525 "scopes": scopes,526 },527 )528 )529 super().__init__(530 flows=flows,531 scheme_name=scheme_name,532 description=description,533 auto_error=auto_error,534 )535536 async def __call__(self, request: Request) -> str | None:537 authorization = request.headers.get("Authorization")538 scheme, param = get_authorization_scheme_param(authorization)539 if not authorization or scheme.lower() != "bearer":540 if self.auto_error:541 raise self.make_not_authenticated_error()542 else:543 return None544 return param545546547class OAuth2AuthorizationCodeBearer(OAuth2):548 """549 OAuth2 flow for authentication using a bearer token obtained with an OAuth2 code550 flow. An instance of it would be used as a dependency.551 """552553 def __init__(554 self,555 authorizationUrl: str,556 tokenUrl: Annotated[557 str,558 Doc(559 """560 The URL to obtain the OAuth2 token.561 """562 ),563 ],564 refreshUrl: Annotated[565 str | None,566 Doc(567 """568 The URL to refresh the token and obtain a new one.569 """570 ),571 ] = None,572 scheme_name: Annotated[573 str | None,574 Doc(575 """576 Security scheme name.577578 It will be included in the generated OpenAPI (e.g. visible at `/docs`).579 """580 ),581 ] = None,582 scopes: Annotated[583 dict[str, str] | None,584 Doc(585 """586 The OAuth2 scopes that would be required by the *path operations* that587 use this dependency.588 """589 ),590 ] = None,591 description: Annotated[592 str | None,593 Doc(594 """595 Security scheme description.596597 It will be included in the generated OpenAPI (e.g. visible at `/docs`).598 """599 ),600 ] = None,601 auto_error: Annotated[602 bool,603 Doc(604 """605 By default, if no HTTP Authorization header is provided, required for606 OAuth2 authentication, it will automatically cancel the request and607 send the client an error.608609 If `auto_error` is set to `False`, when the HTTP Authorization header610 is not available, instead of erroring out, the dependency result will611 be `None`.612613 This is useful when you want to have optional authentication.614615 It is also useful when you want to have authentication that can be616 provided in one of multiple optional ways (for example, with OAuth2617 or in a cookie).618 """619 ),620 ] = True,621 ):622 if not scopes:623 scopes = {}624 flows = OAuthFlowsModel(625 authorizationCode=cast(626 Any,627 {628 "authorizationUrl": authorizationUrl,629 "tokenUrl": tokenUrl,630 "refreshUrl": refreshUrl,631 "scopes": scopes,632 },633 )634 )635 super().__init__(636 flows=flows,637 scheme_name=scheme_name,638 description=description,639 auto_error=auto_error,640 )641642 async def __call__(self, request: Request) -> str | None:643 authorization = request.headers.get("Authorization")644 scheme, param = get_authorization_scheme_param(authorization)645 if not authorization or scheme.lower() != "bearer":646 if self.auto_error:647 raise self.make_not_authenticated_error()648 else:649 return None # pragma: nocover650 return param651652653class SecurityScopes:654 """655 This is a special class that you can define in a parameter in a dependency to656 obtain the OAuth2 scopes required by all the dependencies in the same chain.657658 This way, multiple dependencies can have different scopes, even when used in the659 same *path operation*. And with this, you can access all the scopes required in660 all those dependencies in a single place.661662 Read more about it in the663 [FastAPI docs for OAuth2 scopes](https://fastapi.tiangolo.com/advanced/security/oauth2-scopes/).664 """665666 def __init__(667 self,668 scopes: Annotated[669 list[str] | None,670 Doc(671 """672 This will be filled by FastAPI.673 """674 ),675 ] = None,676 ):677 self.scopes: Annotated[678 list[str],679 Doc(680 """681 The list of all the scopes required by dependencies.682 """683 ),684 ] = scopes or []685 self.scope_str: Annotated[686 str,687 Doc(688 """689 All the scopes required by all the dependencies in a single string690 separated by spaces, as defined in the OAuth2 specification.691 """692 ),693 ] = " ".join(self.scopes)
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.