Refresh Tokens

Refresh tokens are long-lived tokens that can be exchanged for new access tokens after an access token expires.

Refresh tokens cannot access an endpoint protected with paseto_required(), and access tokens cannot access an endpoint protected with paseto_required(refresh_token=True).

Access tokens are marked as fresh when they were created from an explicit credential check instead of from a refresh flow. This gives you a way to reserve high-risk operations for recently authenticated users.

When calling a refresh endpoint, send the refresh token instead of the access token:

Authorization: Bearer <refresh_token>

Here is an example of using access and refresh tokens:

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")

    # Use create_access_token() and create_refresh_token() to create our
    # access and refresh tokens
    access_token = Authorize.create_access_token(subject=user.username)
    refresh_token = Authorize.create_refresh_token(subject=user.username)
    return {"access_token": access_token, "refresh_token": refresh_token}


@app.post("/refresh")
def refresh(Authorize: AuthPASETO = Depends()):
    """
    The paseto_required(refresh_token=True) function insures a valid refresh
    token is present in the request before running any code below that function.
    We can use the get_subject() function to get the subject of the refresh
    token, and use the create_access_token() function again to make a new access token
    """
    Authorize.paseto_required(refresh_token=True)

    current_user = Authorize.get_subject()
    new_access_token = Authorize.create_access_token(subject=current_user)
    return {"access_token": new_access_token}


@app.get("/protected")
def protected(Authorize: AuthPASETO = Depends()):
    Authorize.paseto_required()

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