Bluefox Stack

Authentication
for every Bluefox app

JWT tokens, user management, refresh token rotation, and CSRF protection. One function call from zero to a fully authenticated FastAPI application.

Quick start
01

Install

$ uv add bluefox-auth
02

Wire it up

main.py
from bluefox_core import BluefoxSettings, create_bluefox_app
from bluefox_auth import BluefoxAuth

settings = BluefoxSettings()
app = create_bluefox_app(settings)
BluefoxAuth(app, settings)
03

Protect a route

main.py
from fastapi import Depends
from bluefox_auth import current_active_user, BluefoxUser

@app.get("/dashboard")
async def dashboard(user: BluefoxUser = Depends(current_active_user)):
    return {"message": f"Hello, {user.email}"}
Dual transport

Both Bearer header and HttpOnly cookies work out of the box. The right transport is auto-detected per request.

API client (Bearer)
# Login and get tokens
$ curl -X POST /auth/login \
    -d '{"email": "user@example.com", "password": "..."}'

# Use the access token
$ curl /auth/me -H "Authorization: Bearer eyJhbG..."
Browser (cookies)
// Login — cookies are set automatically
await fetch("/auth/login", {
  method: "POST",
  credentials: "include",
  body: JSON.stringify({ email, password }),
});

// Subsequent requests just work
await fetch("/auth/me", { credentials: "include" });
What you get

JWT tokens

Access and refresh tokens with jti, iat, and audience claims. Configurable expiry and algorithm.

Refresh token rotation

Each refresh creates a new token in the same family. Replay a revoked token and the entire family is invalidated.

CSRF protection

Plain double-submit cookie pattern for cookie transport. Bearer requests skip CSRF automatically.

Password security

bcrypt hashing with timing-safe verification. 72-byte limit enforced at the schema level. Dummy hash prevents enumeration.

Password reset

Stateless one-time-use tokens via async email hook. Silent on unknown emails to prevent enumeration.

Email verification

Stateless one-time-use tokens via async email hook. Short-circuits when already verified.

Enable password reset & email verification

Provide async callback hooks and the endpoints light up. No hooks, no 500s — just a clean 501 until you're ready.

main.py
async def send_reset(email: str, token: str) -> None:
    url = f"https://app.example.com/reset?token={token}"
    await mailer.send(to=email, subject="Reset your password", body=url)

async def send_verify(email: str, token: str) -> None:
    url = f"https://app.example.com/verify?token={token}"
    await mailer.send(to=email, subject="Verify your email", body=url)

BluefoxAuth(
    app, settings,
    password_reset_send_fn=send_reset,
    email_verify_send_fn=send_verify,
)