Skip to main content
This example demonstrates how to use fresh tokens to require recent authentication for sensitive operations:
  • Fresh tokens are created when users log in with credentials
  • Non-fresh tokens are created when refreshing
  • Sensitive endpoints can require fresh tokens to ensure the user recently authenticated
  • Standard endpoints accept both fresh and non-fresh tokens

Complete example

from fastapi import FastAPI, HTTPException, Request
from pydantic import BaseModel

from authx import AuthX, AuthXConfig

# Create a FastAPI app
app = FastAPI(title="AuthX Fresh Token Example")

# Configure AuthX
auth_config = AuthXConfig(
    JWT_ALGORITHM="HS256",
    JWT_SECRET_KEY="your-secret-key",  # In production, use a secure key and store it in environment variables
    JWT_TOKEN_LOCATION=["headers"],
    JWT_HEADER_TYPE="Bearer",
)

# Initialize AuthX
auth = AuthX(config=auth_config)

# Register error handlers
auth.handle_errors(app)


# Define models
class User(BaseModel):
    username: str
    password: str


# Sample user database (in a real app, you would use a database)
USERS = {
    "user1": {"password": "password1", "email": "[email protected]"},
    "user2": {"password": "password2", "email": "[email protected]"},
}


@app.post("/login")
def login(user: User):
    """Login endpoint that validates credentials and returns a fresh token."""
    # Check if user exists and password is correct
    if user.username in USERS and USERS[user.username]["password"] == user.password:
        # Create a fresh token with the username as the subject
        fresh_token = auth.create_access_token(user.username, fresh=True)
        return {"fresh_token": fresh_token, "token_type": "bearer"}

    # Return error if credentials are invalid
    raise HTTPException(status_code=401, detail="Invalid username or password")


@app.post("/refresh")
async def refresh_token(request: Request):
    """Refresh endpoint that creates a non-fresh token using a fresh token."""
    try:
        # Get the token from the request
        token = await auth.get_access_token_from_request(request)

        # Verify the token
        payload = auth.verify_token(token)

        # Create a non-fresh token
        access_token = auth.create_access_token(payload.sub, fresh=False)

        return {"access_token": access_token, "token_type": "bearer"}
    except Exception as e:
        print(f"Refresh error: {str(e)}")
        raise HTTPException(status_code=401, detail=str(e)) from e


@app.get("/protected")
async def protected_route(request: Request):
    """Protected route that requires a valid token (fresh or non-fresh)."""
    try:
        # Get the token from the request
        token = await auth.get_access_token_from_request(request)

        # Verify the token
        payload = auth.verify_token(token)

        # Get the username from the token subject
        username = payload.sub

        # Return user information
        return {
            "message": "You have access to this protected resource",
            "username": username,
            "email": USERS.get(username, {}).get("email"),
            "fresh": payload.fresh,
        }
    except Exception as e:
        print(f"Authentication error: {str(e)}")
        raise HTTPException(status_code=401, detail=str(e)) from e


@app.get("/fresh-required")
async def fresh_required_route(request: Request):
    """Protected route that requires a fresh token."""
    try:
        # Get the token from the request
        token = await auth.get_access_token_from_request(request)

        # Verify the token
        payload = auth.verify_token(token)

        # Check if the token is fresh
        if not payload.fresh:
            raise HTTPException(status_code=401, detail="Fresh token required")

        # Get the username from the token subject
        username = payload.sub

        # Return user information
        return {
            "message": "You have access to this fresh-required resource",
            "username": username,
            "email": USERS.get(username, {}).get("email"),
        }
    except Exception as e:
        print(f"Authentication error: {str(e)}")
        raise HTTPException(status_code=401, detail=str(e)) from e


@app.get("/")
def read_root():
    """Public route that doesn't require authentication."""
    return {
        "message": "Welcome to AuthX Fresh Token Example",
        "endpoints": {
            "login": "POST /login - Get a fresh token",
            "refresh": "POST /refresh - Get a non-fresh token using a fresh token",
            "protected": "GET /protected - Access protected resource (requires any token)",
            "fresh-required": "GET /fresh-required - Access protected resource (requires fresh token)",
        },
    }


if __name__ == "__main__":
    import os

    import uvicorn

    port = int(os.environ.get("PORT", 8000))
    uvicorn.run(app, host="0.0.0.0", port=port)

How it works

1

Create fresh tokens on login

When users provide credentials, create a fresh token by setting fresh=True in auth.create_access_token().
2

Create non-fresh tokens on refresh

When refreshing tokens, create non-fresh tokens by setting fresh=False. This indicates the user hasn’t recently entered credentials.
3

Check freshness for sensitive operations

For sensitive endpoints (like changing passwords, updating payment methods, etc.), check payload.fresh and reject non-fresh tokens.
Fresh tokens provide an additional security layer for sensitive operations without requiring a completely separate authentication mechanism.

Running the example

1

Install dependencies

pip install authx-python fastapi uvicorn
2

Run the server

python fresh_token.py
3

Login to get a fresh token

curl -X POST http://localhost:8000/login \
  -H "Content-Type: application/json" \
  -d '{"username":"user1","password":"password1"}'
Response:
{
  "fresh_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "token_type": "bearer"
}
4

Access fresh-required endpoint

With a fresh token, you can access the sensitive endpoint:
curl http://localhost:8000/fresh-required \
  -H "Authorization: Bearer <fresh_token>"
5

Refresh to get a non-fresh token

curl -X POST http://localhost:8000/refresh \
  -H "Authorization: Bearer <fresh_token>"
Response:
{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "token_type": "bearer"
}
6

Try accessing with non-fresh token

Non-fresh tokens work for standard endpoints:
curl http://localhost:8000/protected \
  -H "Authorization: Bearer <non_fresh_token>"
But they’re rejected by fresh-required endpoints:
curl http://localhost:8000/fresh-required \
  -H "Authorization: Bearer <non_fresh_token>"
# Returns: {"detail": "Fresh token required"}

Use cases

Fresh tokens are ideal for operations that require recent authentication:
  • Password changes: Ensure the user recently logged in before allowing password updates
  • Payment operations: Require fresh authentication for financial transactions
  • Account deletion: Verify the user is actively authenticated before deleting their account
  • Security settings: Require fresh tokens when modifying two-factor authentication or other security settings
  • Sensitive data access: Protect highly sensitive information by requiring recent authentication
You can combine fresh tokens with refresh tokens: login gives a fresh access token and a refresh token, refreshing gives a non-fresh access token.

Build docs developers (and LLMs) love