-from typing import List, Optional
+from typing import Optional
from fastapi.openapi.models import OAuth2 as OAuth2Model, OAuthFlows as OAuthFlowsModel
from fastapi.params import Form
from fastapi.security.base import SecurityBase
-from pydantic import BaseModel, Schema
from starlette.exceptions import HTTPException
from starlette.requests import Request
from starlette.status import HTTP_403_FORBIDDEN
-class OAuth2PasswordRequestData(BaseModel):
- grant_type: str = "password"
- username: str
- password: str
- scope: Optional[List[str]] = None
- # Client ID and secret might come from headers
- client_id: Optional[str] = None
- client_secret: Optional[str] = None
-
-
class OAuth2PasswordRequestForm:
"""
This is a dependency class, use it like:
data = form_data.parse()
print(data.username)
print(data.password)
- for scope in data.scope:
+ for scope in data.scopes:
print(scope)
if data.client_id:
print(data.client_id)
It creates the following Form request parameters in your endpoint:
grant_type: the OAuth2 spec says it is required and MUST be the fixed string "password".
- Nevertheless, this model is permissive and allows not passing it. If you want to enforce it,
- use instead the OAuth2PasswordRequestFormStrict model.
+ Nevertheless, this dependency class is permissive and allows not passing it. If you want to enforce it,
+ use instead the OAuth2PasswordRequestFormStrict dependency.
username: username string. The OAuth2 spec requires the exact field name "username".
password: password string. The OAuth2 spec requires the exact field name "password".
scope: Optional string. Several scopes (each one a string) separated by spaces. E.g.
using HTTP Basic auth, as: client_id:client_secret
client_secret: optional string. OAuth2 recommends sending the client_id and client_secret (if any)
using HTTP Basic auth, as: client_id:client_secret
-
-
- It has the method parse() that returns a model with all the same data and the scopes extracted as a list of strings.
"""
def __init__(
self.grant_type = grant_type
self.username = username
self.password = password
- self.scope = scope
+ self.scopes = scope.split()
self.client_id = client_id
self.client_secret = client_secret
- def parse(self) -> OAuth2PasswordRequestData:
- return OAuth2PasswordRequestData(
- grant_type=self.grant_type,
- username=self.username,
- password=self.password,
- scope=self.scope.split(),
- client_id=self.client_id,
- client_secret=self.client_secret,
- )
-
class OAuth2PasswordRequestFormStrict(OAuth2PasswordRequestForm):
- # The OAuth2 spec says it MUST have the value "password"
- grant_type: str = Schema(..., regex="password")
+ """
+ This is a dependency class, use it like:
+
+ @app.post("/login")
+ def login(form_data: Oauth2PasswordRequestFormStrict = Depends()):
+ data = form_data.parse()
+ print(data.username)
+ print(data.password)
+ for scope in data.scopes:
+ print(scope)
+ if data.client_id:
+ print(data.client_id)
+ if data.client_secret:
+ print(data.client_secret)
+ return data
+
+
+ It creates the following Form request parameters in your endpoint:
+
+ grant_type: the OAuth2 spec says it is required and MUST be the fixed string "password".
+ This dependency is strict about it. If you want to be permissive, use instead the
+ OAuth2PasswordRequestFormStrict dependency class.
+ username: username string. The OAuth2 spec requires the exact field name "username".
+ password: password string. The OAuth2 spec requires the exact field name "password".
+ scope: Optional string. Several scopes (each one a string) separated by spaces. E.g.
+ "items:read items:write users:read profile openid"
+ client_id: optional string. OAuth2 recommends sending the client_id and client_secret (if any)
+ using HTTP Basic auth, as: client_id:client_secret
+ client_secret: optional string. OAuth2 recommends sending the client_id and client_secret (if any)
+ using HTTP Basic auth, as: client_id:client_secret
+ """
+
+ def __init__(
+ self,
+ grant_type: str = Form(..., regex="password"),
+ username: str = Form(...),
+ password: str = Form(...),
+ scope: str = Form(""),
+ client_id: Optional[str] = Form(None),
+ client_secret: Optional[str] = Form(None),
+ ):
+ super().__init__(
+ grant_type=grant_type,
+ username=username,
+ password=password,
+ scope=scope,
+ client_id=client_id,
+ client_secret=client_secret,
+ )
class OAuth2(SecurityBase):