Usage
Now that you have setup everything, lets get started using
fastapi-login
.
Login route
First we need to create a login route for our users.
from fastapi import Depends
from fastapi.security import OAuth2PasswordRequestForm
from fastapi_login.exceptions import InvalidCredentialsException
@app.post('/login')
def login(data: OAuth2PasswordRequestForm = Depends()):
email = data.username
password = data.password
user = query_user(email)
if not user:
# you can return any response or error of your choice
raise InvalidCredentialsException
elif password != user['password']:
raise InvalidCredentialsException
return {'status': 'Success'}
Note
We use the same url("/login"
) we have used as the token_url
argument,
when initiating our LoginManager
instance
Returning token
Now that we have created a login route, we want to return a token, which can than be used to access protected routes.
@app.post('/login')
def login(data: OAuth2PasswordRequestForm = Depends()):
email = data.username
password = data.password
user = query_user(email)
if not user:
# you can return any response or error of your choice
raise InvalidCredentialsException
elif password != user['password']:
raise InvalidCredentialsException
access_token = manager.create_access_token(
data={'sub': email}
)
return {'access_token': access_token}
Bug
LoginManager
expects the parameter used in your LoginManager.user_loader
function to be in the sub
field of the token. This conforms the official
specification of json web tokens.
Usage as a dependency
After the user has way to obtain an access_token, the LoginManager
instance
can be used as a dependency.
@app.get('/protected')
def protected_route(user=Depends(manager)):
return {'user': user}
Note
user
in this case will be whatever the LoginManager.user_loader
decorated function returns.
In case user is None
the LoginManager.not_authenticated_exception
will be thrown, this results by default to
fastapi_login.exceptions.InvalidCredentialsException
.
If a custom exception has been set by the user it will be
raised instead.
Warning
By default the token is expected to be in the Authorization
header
value fo the request and of the following format:
Bearer <token>
Returning None instead of raising an exception
In case that one wishes to handle the case of an unauthorized user, differently than returning an exception
since version 1.9.0
it is possible to use the optional
method:
@app.get('/protected')
def protected_route(user=Depends(manager.optional)):
if user is None:
# Do something ...
return {'user': user}
Note
This catches all exceptions that are raised while trying to authenticate a user.
This might lead to cases where valid exception from e.g. the database or FastAPI are caught.
If you aware of a solution that allows to catch custom exception that are subclasses of HTTPException
or Exception
, please let me know. See also #47
and #78 for more discussion on this topic.