Validation and Custom Types

FastAPI PASETO exposes validation controls for issuer, audience, custom token types, base64-encoded tokens, and token-binding options such as implicit assertions.

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

from fastapi_paseto import AuthPASETO
from fastapi_paseto.exceptions import AuthPASETOException

app = FastAPI()


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


ISSUER = "https://auth.example.com"
AUDIENCE = ["urn:customers"]


@AuthPASETO.load_config
def get_config():
    return {
        "authpaseto_secret_key": "secret",
        "authpaseto_encode_issuer": ISSUER,
        "authpaseto_decode_issuer": ISSUER,
        "authpaseto_decode_audience": AUDIENCE,
    }


@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,
        audience=AUDIENCE,
    )
    base64_token = Authorize.create_access_token(
        subject=user.username,
        audience=AUDIENCE,
        base64_encode=True,
    )
    email_verify_token = Authorize.create_token(
        subject=user.username,
        type="email-verify",
        audience=AUDIENCE,
        issuer=ISSUER,
    )
    return {
        "access_token": access_token,
        "base64_token": base64_token,
        "email_verify_token": email_verify_token,
    }


@app.get("/audience-protected")
def audience_protected(Authorize: AuthPASETO = Depends()):
    Authorize.paseto_required()
    return {"user": Authorize.get_subject()}


@app.get("/base64-protected")
def base64_protected(Authorize: AuthPASETO = Depends()):
    Authorize.paseto_required(base64_encoded=True)
    return {"user": Authorize.get_subject()}


@app.get("/email-verify")
def email_verify(Authorize: AuthPASETO = Depends()):
    Authorize.paseto_required(type="email-verify")
    return {"user": Authorize.get_subject()}

Use these options when you need stronger contracts than "any valid access token":

  • Set authpaseto_decode_issuer to require an iss claim with a specific value.
  • Pass audience= when creating a token and set authpaseto_decode_audience to enforce the expected audience on decode.
  • Use create_token(type="...") together with paseto_required(type="...") for custom token flows such as email verification.
  • Use base64_encode=True when creating a token and paseto_required(base64_encoded=True) when validating it.
  • Use implicit_assertion= on both creation and validation when a token must be bound to external request context.

Important issuer detail:

  • authpaseto_encode_issuer automatically adds iss only to create_access_token().
  • authpaseto_decode_issuer applies to every decoded token.
  • If you enable issuer validation for refresh or custom tokens, pass issuer= when creating those tokens.

For footer handling and get_token_footer(), see Footers and Assertions.