Skip to main content
This guide covers the fundamental steps for implementing JWT authentication with AuthX. You’ll learn how to configure AuthX, create tokens, and protect routes.

Initial setup

1

Install AuthX

Install the package using pip:
pip install authx
2

Configure AuthX

Create an AuthX configuration with your secret key and token settings:
from authx import AuthX, AuthXConfig

auth_config = AuthXConfig(
    JWT_ALGORITHM="HS256",
    JWT_SECRET_KEY="your-secret-key",  # Store in environment variables
    JWT_TOKEN_LOCATION=["headers"],
    JWT_HEADER_TYPE="Bearer",
)

auth = AuthX(config=auth_config)
Never hardcode your JWT_SECRET_KEY in production. Use environment variables or a secure secrets management system.
3

Register error handlers

Enable automatic error handling for AuthX exceptions:
from fastapi import FastAPI

app = FastAPI()
auth.handle_errors(app)
This automatically handles all AuthX exceptions with appropriate HTTP status codes and error messages.

Creating tokens

Generate JWT tokens for authenticated users:
from fastapi import HTTPException
from pydantic import BaseModel

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

@app.post("/login")
def login(data: LoginRequest):
    # Validate credentials (use proper password hashing in production)
    if data.username in USERS and USERS[data.username]["password"] == data.password:
        # Create access token with username as subject
        access_token = auth.create_access_token(uid=data.username)
        return {"access_token": access_token, "token_type": "bearer"}
    
    raise HTTPException(status_code=401, detail="Invalid credentials")
The uid parameter (user identifier) becomes the sub (subject) claim in the JWT. This can be any unique identifier like a username, email, or user ID.

Protecting routes

There are multiple ways to protect your routes with AuthX:

Method 1: Manual token verification

Manually retrieve and verify tokens in your route:
from fastapi import Request

@app.get("/protected")
async def protected_route(request: Request):
    # Get the token from the request
    token = await auth.get_access_token_from_request(request)
    
    # Verify the token
    payload = auth.verify_token(token)
    
    # Access token claims
    username = payload.sub
    
    return {
        "message": "Access granted",
        "username": username
    }

Method 2: Using dependencies

Use FastAPI’s dependency injection for cleaner code:
from fastapi import Depends
from authx.schema import TokenPayload

@app.get("/protected")
async def protected_route(
    payload: TokenPayload = Depends(auth.access_token_required)
):
    return {
        "message": "Access granted",
        "username": payload.sub
    }

Method 3: Using the ACCESS_REQUIRED property

AuthX provides convenient property shortcuts:
@app.get("/protected")
async def protected_route(payload: TokenPayload = auth.ACCESS_REQUIRED):
    return {
        "message": "Access granted",
        "username": payload.sub,
        "is_fresh": payload.fresh
    }

Working with token payloads

The TokenPayload object contains all JWT claims:
@app.get("/profile")
async def get_profile(payload: TokenPayload = auth.ACCESS_REQUIRED):
    return {
        "sub": payload.sub,           # Subject (user identifier)
        "jti": payload.jti,           # JWT ID (unique token identifier)
        "type": payload.type,         # Token type ("access" or "refresh")
        "fresh": payload.fresh,       # Whether token is fresh
        "iat": payload.iat,           # Issued at timestamp
        "exp": payload.exp,           # Expiration timestamp
        "iss": payload.iss,           # Issuer
        "aud": payload.aud,           # Audience
    }

Adding custom data to tokens

Store additional information in your tokens:
@app.post("/login")
def login(data: LoginRequest):
    user = USERS[data.username]
    
    # Add custom data to the token
    access_token = auth.create_access_token(
        uid=data.username,
        data={
            "email": user["email"],
            "role": user["role"],
            "plan": user["plan"]
        }
    )
    
    return {"access_token": access_token, "token_type": "bearer"}
Access custom data from the payload:
@app.get("/dashboard")
async def dashboard(payload: TokenPayload = auth.ACCESS_REQUIRED):
    # Access custom data using extra_dict
    custom_data = payload.extra_dict
    
    return {
        "username": payload.sub,
        "email": custom_data.get("email"),
        "role": custom_data.get("role"),
        "plan": custom_data.get("plan")
    }

Complete example

Here’s a complete working example:
from fastapi import FastAPI, HTTPException, Request, Depends
from pydantic import BaseModel
from authx import AuthX, AuthXConfig
from authx.schema import TokenPayload

app = FastAPI()

# Configure AuthX
auth_config = AuthXConfig(
    JWT_ALGORITHM="HS256",
    JWT_SECRET_KEY="your-secret-key",
    JWT_TOKEN_LOCATION=["headers"],
    JWT_HEADER_TYPE="Bearer",
)

auth = AuthX(config=auth_config)
auth.handle_errors(app)

# User model
class LoginRequest(BaseModel):
    username: str
    password: str

# Sample user database
USERS = {
    "user1": {"password": "password1", "email": "user1@example.com"},
    "user2": {"password": "password2", "email": "user2@example.com"},
}

@app.post("/login")
def login(data: LoginRequest):
    """Login endpoint that returns an access token."""
    if data.username in USERS and USERS[data.username]["password"] == data.password:
        access_token = auth.create_access_token(uid=data.username)
        return {"access_token": access_token, "token_type": "bearer"}
    
    raise HTTPException(status_code=401, detail="Invalid credentials")

@app.get("/protected")
async def protected_route(payload: TokenPayload = auth.ACCESS_REQUIRED):
    """Protected route that requires authentication."""
    return {
        "message": "Access granted",
        "username": payload.sub,
        "email": USERS.get(payload.sub, {}).get("email")
    }

@app.get("/")
def read_root():
    """Public endpoint."""
    return {"message": "Welcome to AuthX"}

Testing with curl

1

Login to get a token

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

Access protected route

curl http://localhost:8000/protected \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
Response:
{
  "message": "Access granted",
  "username": "user1",
  "email": "user1@example.com"
}

Next steps

Access and refresh tokens

Learn how to implement long-lived sessions with refresh tokens

Fresh tokens

Require recent authentication for sensitive operations

Scopes and permissions

Implement fine-grained access control with scopes

Cookie authentication

Use secure HTTP-only cookies for token storage

Build docs developers (and LLMs) love