Skip to content

Quickstart

A complete, runnable credentials app in five minutes. We use SQLite (ships with standard) and JSON token delivery.

1. Install

pip install "sreekarnv-fastauth[standard]"

2. Create main.py

from contextlib import asynccontextmanager

from fastapi import Depends, FastAPI
from fastauth import FastAuth, FastAuthConfig
from fastauth.adapters.sqlalchemy import SQLAlchemyAdapter
from fastauth.api.deps import require_auth
from fastauth.providers.credentials import CredentialsProvider
from fastauth.types import UserData

adapter = SQLAlchemyAdapter(engine_url="sqlite+aiosqlite:///./auth.db")

# Generate a real secret with `fastauth generate-secret` and paste it here.
SECRET = "change-me-in-production-min-32-bytes!!"

auth = FastAuth(FastAuthConfig(
    secret=SECRET,
    providers=[CredentialsProvider()],
    adapter=adapter.user,
    token_adapter=adapter.token,
))

@asynccontextmanager
async def lifespan(app: FastAPI):
    await adapter.create_tables()
    yield

app = FastAPI(lifespan=lifespan)
auth.mount(app)

@app.get("/dashboard")
async def dashboard(user: UserData = Depends(require_auth)):
    return {"hello": user["email"], "id": user["id"]}

3. Run

uvicorn main:app --reload

adapter.create_tables() runs on startup and creates the fastauth_* tables (CREATE IF NOT EXISTS).

4. Register and log in

# Register
curl -X POST http://localhost:8000/auth/register \
  -H "Content-Type: application/json" \
  -d '{"email":"a@b.com","password":"s3cur3-pw!","name":"A"}'
# -> 201 {"access_token": "...", "refresh_token": "...", "token_type": "bearer", "expires_in": 900}

# Log in
RESP=$(curl -s -X POST http://localhost:8000/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"a@b.com","password":"s3cur3-pw!"}')
ACCESS=$(python -c "import json; print(json.loads('''$RESP''')['access_token'])")

# hit a protected route
curl http://localhost:8000/dashboard -H "Authorization: Bearer $ACCESS"
# -> {"hello":"a@b.com","id":"..."}

5. What just happened

  • FastAuthConfig is the configuration object; the three required fields are secret, providers, and adapter.
  • adapter.user is a UserAdapter; adapter.token is a TokenAdapter used to persist one-time verification/reset tokens and to enforce refresh-token revocation/replay protection. require_token_adapter_for_refresh defaults to True, so token_adapter is required to issue refresh tokens.
  • auth.mount(app) includes the /auth/* router at the configured route_prefix (default /auth).
  • require_auth is a FastAPI dependency that reads the access token from Authorization: Bearer or the access_token cookie, decodes it, and returns the UserData record. It raises 401 if absent/expired or the account is inactive.

Where to go next

Common mistakes

  • ConfigError: 'secret' must be at least 32 bytes — HS256 (the default) requires a ≥32-byte secret. Run fastauth generate-secret.
  • ConfigError: token_adapter is required when require_token_adapter_for_refresh=True — you must pass token_adapter=adapter.token (or set require_token_adapter_for_refresh=False only for tests/demos).
  • Forgetting await adapter.create_tables() in the lifespan — endpoints then return 500 because tables don't exist.
  • 401 Not authenticated on /dashboard — you sent the refresh token instead of the access token, or the JWT is expired. Refresh with POST /auth/refresh (body {"refresh_token": "..."}).