FastAPI JWT Auth & RBAC Starter
Overview
A FastAPI authentication and authorization layer with short-lived JWT access tokens and long-lived opaque refresh tokens that are stored server-side as SHA-256 digests, rotated on every refresh, and grouped into per-login families. Presenting a refresh token that has already been rotated away revokes that whole family, and a token_version column lets log-out-everywhere invalidate outstanding access tokens without a blocklist. Authorization uses database-backed roles and granular permissions with parent-role inheritance, exposed as require_permission() and require_role() dependencies that return 403 bodies naming what was required and what the caller holds. Ships with Alembic migrations, an admin CLI, Argon2id hashing, in-process rate limiting, structured JSON auth logging, and 59 pytest tests that were run and passed on CPython 3.11, 3.12, 3.13 and 3.14. Runs on SQLite with no setup. The PostgreSQL path (asyncpg) is wired and documented but has never been executed by the author, so the package includes a docker-compose file for postgres:17-alpine and a one-command script that applies the migrations and runs the whole suite against it, letting the buyer exercise that path themselves before relying on it.
Source preview
if record.is_used or record.is_revoked:
revoked = await revoke_family(
session,
family_id=record.family_id,
reason=RevocationReason.REUSE_DETECTED,
)
log_auth_event(
AuthEvent.REFRESH_REUSE_DETECTED,
level=logging.ERROR,
user_id=str(record.user_id),
family_id=str(record.family_id),
token_id=str(record.id),
already_used=record.is_used,
already_revoked=record.is_revoked,
tokens_revoked=revoked,
client_ip=client.truncated_ip(),
user_agent=client.truncated_user_agent(),
)
raise AuthenticationError(
_GENERIC_REFRESH_FAILURE, code="refresh_token_reuse_detected"
)Excludes tax, added at checkout where it applies.