Package: fastapi-login
FastAPI-LoginFastAPI-Login tries to provide similar functionality asFlask-Logindoes.DocumentationIn-depth documentation can be found atfastapi-login.readthedocs.ioSome examples can be foundhereInstallationpipinstallfastapi-loginUsageTo begin we have to setup our FastAPI app:fromfastapiimportFastAPISECRET='your-secret-key'app=FastAPI()To obtain a suitable secret key you can runimport os; print(os.urandom(24).hex()).Now we can import and setup the LoginManager, which will handle the process of
encoding and decoding our Json Web Tokens.fromfastapi_loginimportLoginManagermanager=LoginManager(SECRET,token_url='/auth/token')For the example we will use a dictionary to represent our user database. In your
application this could also be a real database like sqlite or Postgres. It does not
matter as you have to provide the function which retrieves the user.fake_db={'johndoe@e.mail':{'password':'hunter2'}}Now we have to provide theLoginManagerwith a way to load our user. Theuser_loadercallback should either return your user object orNone@manager.user_loader()defload_user(email:str):# could also be an asynchronous functionuser=fake_db.get(email)returnuserNow we have to define a way to let the user login in our app. Therefore we will create
a new route:fromfastapiimportDependsfromfastapi.securityimportOAuth2PasswordRequestFormfromfastapi_login.exceptionsimportInvalidCredentialsException# the python-multipart package is required to use the OAuth2PasswordRequestForm@app.post('/auth/token')deflogin(data:OAuth2PasswordRequestForm=Depends()):email=data.usernamepassword=data.passworduser=load_user(email)# we are using the same function to retrieve the userifnotuser:raiseInvalidCredentialsException# you can also use your own HTTPExceptionelifpassword!=user['password']:raiseInvalidCredentialsExceptionaccess_token=manager.create_access_token(data=dict(sub=email))return{'access_token':access_token,'token_type':'bearer'}Now whenever you want your user to be logged in to use a route, you can simply
use yourLoginManagerinstance as a dependency.@app.get('/protected')defprotected_route(user=Depends(manager)):...If you also want to handle a not authenticated error, you can add your own subclass of Exception to the LoginManager.fromstarlette.responsesimportRedirectResponseclassNotAuthenticatedException(Exception):pass# these two argument are mandatorydefexc_handler(request,exc):returnRedirectResponse(url='/login')# This will be deprecated in the future# set your exception when initiating the instance# manager = LoginManager(..., custom_exception=NotAuthenticatedException)manager.not_authenticated_exception=NotAuthenticatedException# You also have to add an exception handler to your app instanceapp.add_exception_handler(NotAuthenticatedException,exc_handler)To change the expiration date of the token use theexpires_deltaargument of thecreate_access_tokenmethod
with a timedelta. The default is set 15 min. Please be aware that setting a long expiry date is not considered a good practice
as it would allow an attacker with the token to use your application as long as he wants.fromdatetimeimporttimedeltadata=dict(sub=user.email)# expires after 15 mintoken=manager.create_access_token(data=data)# expires after 12 hourslong_token=manager.create_access_token(data=data,expires=timedelta(hours=12))Usage with cookiesInstead of checking the header for the token.fastapi-loginalso support access using cookies.fromfastapi_loginimportLoginManagermanager=LoginManager(SECRET,token_url='/auth/token',use_cookie=True)Now the manager will check the requests cookies the headers for the access token. The name of the cookie can be set usingmanager.cookie_name.
If you only want to check the requests cookies you can turn the headers off using theuse_headerargumentFor convenience the LoginManager also includes theset_cookiemethod which sets the cookie to your response,
with the recommended HTTPOnly flag and themanager.cookie_nameas the key.fromfastapiimportDependsfromstarlette.responsesimportResponse@app.get('/auth')defauth(response:Response,user=Depends(manager)):token=manager.create_access_token(data=dict(sub=user.email))manager.set_cookie(response,token)returnresponse