Reference
Reference#
Utility classes to use for authentication in FastAPI.
The purpose of this module is to reduce the boilerplate authentication code written for FastAPI. It is based on the code that you can find at OAuth2 with Password (and hashing), Bearer with JWT tokens.
- class Authenticator(key: str, /, algorithm: str = 'HS256', cookie_name: str = 'fastapi_token', path: str = 'token', exp: datetime.timedelta = datetime.timedelta(seconds=3600), public_key=None)[source]#
Provides authentication for FastAPI endpoints.
Here’s an example of creating the authenticator from a secret key stored in an environment variable.
import os from jwtdown_fastapi import Authenticator class MyAuth(Authenticator): # Implement the abstract methods auth = MyAuth(os.environ["SECRET_KEY"])
- Parameters
key (
str) – The cryptographically strong signing key for JWTs. If using certificates, provide the private key in the form of a string of its contents.algorithm (
str) – The algorithm to use to sign JWTs. Defaults to jose.constants.ALGORITHMS.HS256. If you are using public-private keys, use jose.constants.ALGORITHMS.RS256cookie_name (
str) – The name of the cookie to set in the browser. Defaults to the value offastapi_token.path (
str) – The path that authentication requests will go to. Defaults to “token”.public_key – If using certificates, provide the public key in the form of a string of its contents.
- COOKIE_NAME = 'fastapi_token'#
The override value for the cookie name set by the authenticator.
You can override the cookie name used by the authenticator with code like this.
import os from jwtdown_fastapi import Authenticator class MyAuth(Authenticator): COOKIE_NAME = "custom_cookie_name" # Implement the abstract methods
- abstract async get_account_data(username: str, account_getter: Any) Optional[Union[pydantic.main.BaseModel, dict]][source]#
Get the user based on a username.
You MUST implement this method in your custom class!
This method uses the
account_getterreturned fromget_account_getteras the third argument. It’s the job of this method to get the account data for the providedusername.usernamecan be an email!def get_account_data( self, username: str, account_repo: AccountRepository, ) -> Account: return account_repo.get(username)
- Parameters
username (
str) – This is the value passed as theusernamein the log in form. It is the value that uniquely identifies a user in your application, such as a username or email.account_getter (
Optional[Any]) – Whatever thing you returned fromaccount_getter.
- Returns
account_data – If the account information exists, it should return a Pydantic model or dictionary. If the account information does not exist, then this should return
None.- Return type
Optional[Union[BaseModel, dict]]
- get_account_data_for_cookie(account_data: Union[pydantic.main.BaseModel, dict]) Tuple[str, dict][source]#
Converts account data to a dictionary
This default implementation can accept either a Pydantic model or a dictionary. The value _must_ contain the “email” property/key for the subject claim of the JWT that is generated from this data.
If the resulting dictionary contains a key that is “password”, then it will remove that key from the data for the cookie.
# Implement this method if your account model # does NOT have an email property on/in it. def get_account_data_for_cookie( self, account: AccountOut ) -> Tuple[str, dict]: return account.username, account.dict()
- Parameters
account_data (
Union[BaseModel, dict]) – This will be whatever value is returned from get_account_data- Raises
BadAccountDataError – If the account_data cannot be converted into a dictionary.
- Returns
sub (
str) – This is the value for the “sub” claim of the JWT.data (
dict) – This is the data that will be encoded into the “account” claim of the JWT.
- abstract get_account_getter(account_getter: Any) Any[source]#
Gets the thing that gets account data for your application
You MUST implement this method in your custom class!
This method can be used to resolve your account getter, or just for returning the function or object that you use to get your account data.
A typical implementation of this is just to use dependency injection for the thing you want from FastAPI, then return it. In the following code example, you have some class named
AccountRepositorythat you use to get your account data. The implementation would look like this:def get_account_getter( self, account_repo: AccountRepository = Depends(), ) -> AccountRepository: return account_repo
- async get_current_account_data(account: dict = Depends(try_get_current_account_data)) dict[source]#
Get account data for a request
Like try_get_current_account_data, but raises an error if the account data cannot be found.
Use this method as a
Dependswhen you want to protect and endpoint to only be accessible by an someone that’s got a JWT from logging in.If the token does not exist, the method will raise a 401 error.
@router.post("/api/things") async def create_thing( account_data: dict = Depends(authenticator.get_current_account_data), ): pass
- Raises
HTTPException – If account data cannot be decoded from the JWT.
- Returns
data – Returns the account data from the bearer token in the Authorization header or token. If the function can’t decode the token, then it returns
None.- Return type
dict
- get_exp(proposed: datetime.timedelta, account: Optional[Union[pydantic.main.BaseModel, dict]]) datetime.timedelta[source]#
Returns the amount of time before the JWT expires.
By default, returns the value passed into the exp parameter of the initializer.
This method was introduced in v0.3.0.
- Returns
expiry – The interval for which the JWT should be valid from its point of creation.
- Return type
timedelta
- abstract get_hashed_password(account_data: Union[pydantic.main.BaseModel, dict]) Optional[str][source]#
Gets the hashed password from account data.
You MUST implement this method in your custom class!
Just return the hashed password from the data that you get from your data store for the account.
def get_hashed_password(self, account: Account): return account.hashed_password
- Parameters
account_data (
Union[BaseModel, dict]) – This will be whatever value is returned fromget_account_data- Returns
hashed_password – This is the hashed password stored when creating an account (because you should not store passwords in the clear anywhere)
- Return type
str
- get_session_getter(session_getter: Optional[Any] = None) Any[source]#
Returns the object that handles session manipulation.
This method can be used to resolve your session getter, or just for returning the function or object that you use to get your session data.
A typical implementation of this is just to use dependency injection for the thing you want from FastAPI, then return it. In the following code example, you have some class named
SessionRepositorythat you use to get your account data. The implementation would look like this:def get_session_getter( self, session_repo: SessionRepository = Depends(), ) -> SessionRepository: return session_repo
- Returns
session_getter – By default, this returns None
- Return type
Any
- hash_password(plain_password) str[source]#
Hashes a password for secure storage.
Use this method to hash your passwords so that they can later be verified by the authentication mechanism used by the
Authenticator.Use this method if you allow people to sign up for an account, for example. See the Quick Start.
- async jti_created(jti: str, account: Union[pydantic.main.BaseModel, dict], session_getter: Any)[source]#
Handles when new JTIs are created.
- Parameters
jti (
str) – The new JWT identifieraccount (
Union[BaseModel, dict]) – The account information for which the JWT is being createdsession_getter (
Any) – The value returned from get_session_getter
- async jti_destroyed(jti: str, session_getter: Any)[source]#
Handles when JTIs are destroyed.
- Parameters
jti (
str) – The JWT identifier that is being destroyedsession_getter (
Any) – The value returned from get_session_getter
- async login(response: starlette.responses.Response, request: starlette.requests.Request, form: fastapi.security.oauth2.OAuth2PasswordRequestForm = Depends(NoneType), account_getter=Depends(get_account_getter), session_getter=Depends(get_session_getter)) jwtdown_fastapi.authentication.Token[source]#
Authenticates credentials for an account.
If the data is correct, this creates a cookie set in the person’s browser that contains the JWT. It also returns a JSON payload that contains the JWT in a property named
access_token.- Parameters
response (
Response) – The response from the FastAPI callrequest (
Request) – The request from the FastAPI callform (
OAuth2PasswordRequestForm) – This can be an object that containsusernameandpasswordattributesaccount_getter (
Any) – This is something to use to get your application’s account informationsession_getter (
Any) – This is something to use to get your application’s session information
- Returns
token – An object with
access_tokenandtoken_typeattributes that contain the token information for use in AJAX calls- Return type
Token
- async logout(request: starlette.requests.Request, response: starlette.responses.Response, session_getter=Depends(get_session_getter), jwt: Optional[dict] = None)[source]#
Logs a person out of their account.
This removes the cookie set in the person’s browser.
- Parameters
request (
Request) – The request from the FastAPI callresponse (
Response) – The response from the FastAPI call
- property router#
Get a FastAPI router that has login and logout handlers.
Use this property to get a router to automatically register the
loginandlogoutpath handlers for your application.from authenticator import authenticator from fastapi import APIRouter app = FastAPI() app.include_router(authenticator.router)
- async try_get_current_account_data(bearer_token: Optional[str] = Depends(OAuth2PasswordBearer), cookie_token: Optional[str] = Cookie(None)) dict[source]#
Get account data for a request
This method will return the dictionary that is in the “account” claim of the JWT found in either the Authorization header or the cookie.
Use this method as a
Dependswhen you want to get the current persons’s account information from their token.If the token does not exist, you’ll get a
None.@router.get("/api/things") async def get_things( account_data: Optional[dict] = Depends(authenticator.try_get_current_account_data), ): if account_data: return personalized_list return general_list
- Returns
data – Returns the account data from the bearer token in the Authorization header or token. If the function can’t decode the token, then it returns
None.- Return type
dict
- async validate_jti(jti: str, session_getter: Any) bool[source]#
Validates that the jti is good.
By default, this returns
True.- Parameters
jti (
str) – The JWT identifier that is being destroyedsession_getter (
Any) – The value returned from get_session_getter
- Returns
is_valid – A value to indicate if the jti is valid.
- Return type
bool