Basic Usage

Create a file basic.py:

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


# callback to get your configuration
@AuthPASETO.load_config
def get_config():
    return {
        # Demo only. Generate a strong secret and load it from secure storage in
        # production. See the key-management documentation.
        "authpaseto_secret_key": "secret"
    }


# exception handler for authpaseto
# in production, you can tweak performance using orjson response
@app.exception_handler(AuthPASETOException)
def authpaseto_exception_handler(request: Request, exc: AuthPASETOException):
    return JSONResponse(status_code=exc.status_code, content={"detail": exc.message})


# provide a method to create access tokens. The create_access_token()
# function is used to actually generate the token to use authorization
# later in endpoint protected
@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")

    # subject identifier for who this token is for example id or username from database
    access_token = Authorize.create_access_token(subject=user.username)
    return {"access_token": access_token}


# protect endpoint with function paseto_required(), which requires
# a valid access token in the request headers to access.
@app.get("/user")
def user(Authorize: AuthPASETO = Depends()):
    Authorize.paseto_required()

    current_user = Authorize.get_subject()
    return {"user": current_user}

The inline "secret" in this demo is only a placeholder for the smallest possible example. In production, generate a high-entropy key and retrieve it from secure storage inside load_config(). See Key Management.

Run the server with:

$ uvicorn basic:app --host 0.0.0.0

INFO:     Started server process [9859]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

By default, paseto_required() reads access tokens from the Authorization header using the Bearer prefix:

Authorization: Bearer <access_token>

You can see the flow with curl:

$ curl http://localhost:8000/user

{"detail":"PASETO Authorization Token required"}

$ curl -H "Content-Type: application/json" -X POST \
  -d '{"username":"test","password":"test"}' http://localhost:8000/login

{"access_token":"v4.local...."}

$ curl -H "Authorization: Bearer <access_token>" http://localhost:8000/user

{"user":"test"}

After paseto_required() succeeds, get_subject() returns the decoded sub claim cached for the current request.