Partially Protecting
In some cases you may want one endpoint to serve both authenticated and
anonymous callers. In that case, use the optional=True argument of
paseto_required().
With optional=True, the route continues when no token is present. It also
continues when a token is present but cannot be decoded, so get_subject() and
get_token_payload() return None in those cases. Checks that happen after a
successful decode, such as token type, freshness, or denylist failures, still
raise an error.
from fastapi import FastAPI, HTTPException, Depends, Request
from fastapi.responses import JSONResponse
from fastapi_paseto import AuthPASETO
from fastapi_paseto.exceptions import AuthPASETOException
from pydantic import BaseModel
app = FastAPI()
class User(BaseModel):
username: str
password: str
@AuthPASETO.load_config
def get_config():
return {"authpaseto_secret_key": "secret"}
@app.exception_handler(AuthPASETOException)
def authpaseto_exception_handler(request: Request, exc: AuthPASETOException):
return JSONResponse(status_code=exc.status_code, content={"detail": exc.message})
@app.post("/login")
def login(user: User, Authorize: AuthPASETO = Depends()):
if user.username != "test" or user.password != "test":
raise HTTPException(status_code=401, detail="Bad username or password")
access_token = Authorize.create_access_token(subject=user.username)
return {"access_token": access_token}
@app.get("/partially-protected")
def partially_protected(Authorize: AuthPASETO = Depends()):
Authorize.paseto_required(optional=True)
# If no paseto is sent in the request, get_subject() will return None
current_user = Authorize.get_subject() or "anonymous"
return {"user": current_user}