Partially Protecting

In some cases you want to use one endpoint for both, protected and unprotected. In this situation you can use function jwt_optional(). This will allow the endpoint to be accessed regardless of if a JWT is sent in the request or not. If a JWT get tampering or expired an error will be returned instead of calling the endpoint.

from fastapi import Depends, FastAPI, HTTPException, Request
from fastapi.responses import JSONResponse
from pydantic import BaseModel

from async_fastapi_jwt_auth import AuthJWT
from async_fastapi_jwt_auth.exceptions import AuthJWTException
from async_fastapi_jwt_auth.auth_jwt import AuthJWTBearer

app = FastAPI()
auth_dep = AuthJWTBearer()


class User(BaseModel):
    username: str
    password: str


class Settings(BaseModel):
    authjwt_secret_key: str = "secret"


@AuthJWT.load_config
def get_config():
    return Settings()


@app.exception_handler(AuthJWTException)
def authjwt_exception_handler(request: Request, exc: AuthJWTException):
    return JSONResponse(status_code=exc.status_code, content={"detail": exc.message})


@app.post("/login")
async def login(user: User, authorize: AuthJWT = Depends(auth_dep)):
    if user.username != "test" or user.password != "test":
        raise HTTPException(status_code=401, detail="Bad username or password")

    access_token = await authorize.create_access_token(subject=user.username)
    return {"access_token": access_token}


@app.get("/partially-protected")
async def partially_protected(authorize: AuthJWT = Depends(auth_dep)):
    await authorize.jwt_optional()

    # If no jwt is sent in the request, get_jwt_subject() will return None
    current_user = await authorize.get_jwt_subject() or "anonymous"
    return {"user": current_user}