Clean-architecture auth core for multiple Python frameworks
Project description
pkg-auth
Clean-architecture identity + ACL for multi-framework Python services. Handles JWT authentication (via Keycloak) and database-backed authorization (users, organizations, roles, permissions, memberships) in a single package with first-class support for FastAPI, Django, and Strawberry GraphQL.
v3.0.0 is a breaking change. The
permissions.is_platformflag is replaced by a tri-statevisibilityenum (platform_only/shared/tenant_only); permissiondescriptionis now a localized JSONB map; and a first-class Service model with a default-deny service guard is added. Seedocs/Upgrade-Service-Guard.mdfor the 3.0.0 upgrade guide. Earlier migrations:docs/MIGRATION_v1.md,docs/MIGRATION_v2.md.
Install
# Core (identity only — no DB deps)
pip install pkg-auth
# With ACL + FastAPI (most common for fritill services)
pip install "pkg-auth[acl-sqlalchemy,fastapi]"
# With ACL + Django
pip install "pkg-auth[acl-django,django]"
# With optional Redis cache
pip install "pkg-auth[cache-redis]"
# Everything
pip install "pkg-auth[all]"
Available extras: acl-sqlalchemy, acl-django, cache-redis, fastapi, django, strawberry, all.
Quickstart (FastAPI)
from fastapi import Depends, FastAPI
from pkg_auth.authentication import IdentityContext
from pkg_auth.authorization import AuthContext
from pkg_auth.integrations.fastapi import (
create_authentication,
make_get_auth_context,
require_permission,
)
# --- Wire authentication + authorization ---
auth = create_authentication(
keycloak_base_url="https://auth.example.com",
realm="fritill",
audience="courses-service",
)
# Mode B (consumer — the common case): pass resolve_user_use_case.
# Mode A (source-of-truth): pass sync_user_use_case instead. Exactly
# one of the two is required; passing both raises ValueError.
get_auth_context = make_get_auth_context(
get_identity=auth.get_identity,
resolve_user_use_case=resolve_user, # or: sync_user_use_case=sync_user (Mode A)
resolve_use_case=resolve,
organization_repo=org_repo,
)
app = FastAPI()
# --- Use in routes ---
@app.get("/courses/{id}")
async def get_course(
id: str,
bundle: tuple[IdentityContext, AuthContext] = Depends(
require_permission("course:view", get_auth_context=get_auth_context)
),
):
identity, auth_ctx = bundle
return {"course_id": id, "roles": sorted(auth_ctx.role_names)}
See examples/itqadem_courses_app for a complete working example.
Features
- Authentication — Keycloak JWT validation producing an
IdentityContext. - Authorization (ACL) — database-backed users, organizations, roles, permissions, and memberships, resolved into a hot-path
AuthContext(role_names,perms). - Permission visibility — tri-state catalog visibility (
platform_only/shared/tenant_only). - Localized descriptions — permission descriptions stored as localized JSONB (
LocalizedText,ACL_DEFAULT_LOCALE). - Services & service guard — first-class
Service/OrganizationServicemodel with a default-deny service guard; the platform org bypasses it. - Mode A / Mode B — be the source of truth for the
userstable, or consume a shared ACL read-only. - Integrations — FastAPI, Django, and Strawberry GraphQL.
- CLIs —
keycloak-init-client,pkg-auth-sync-catalog,pkg-auth-sync-services.
Architecture
pkg_auth/
authentication/ JWT validation → IdentityContext (identity only)
authorization/ Full ACL (users, orgs, roles, perms, memberships)
domain/ Pure entities, ports (Protocol), exceptions
application/use_cases/ Business logic (use cases)
adapters/
sqlalchemy/ Canonical schema + Alembic migrations (0001–0005) + repos
django_orm/ Mirror models (managed=False) + repos
cache/ InMemoryTTLCache / RedisCache + decorator
integrations/
fastapi/ Deps + require_permission + exception handlers
django/ Middleware + decorators
strawberry/ Context getter + permission classes
admin/ Keycloak admin client (user provisioning)
Layering rules: domain has zero external imports; application imports only domain; adapters import their framework; integrations import everything.
Documentation
- Authorization model — schema, permission catalog, roles, memberships, service guard
- Upgrade to the Service Guard (3.0.0)
- Caching — InMemoryTTLCache, RedisCache, invalidation contract
- FastAPI Integration
- Django Integration
- Strawberry Integration
- Keycloak Admin
- Migration v1 · Migration v2
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pkg_auth-3.1.0.tar.gz.
File metadata
- Download URL: pkg_auth-3.1.0.tar.gz
- Upload date:
- Size: 70.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
45098ecee2328ad05bbfeee249bbe83f1d0b06e63df06a89a30fcac5dc1094cf
|
|
| MD5 |
896fc7f5a092efa9e843bcf27e395b92
|
|
| BLAKE2b-256 |
b3dfe6c15a3f20923cb2cfd38e64b8f66fe7e0b4f791a2e559601b509240a50d
|
File details
Details for the file pkg_auth-3.1.0-py3-none-any.whl.
File metadata
- Download URL: pkg_auth-3.1.0-py3-none-any.whl
- Upload date:
- Size: 115.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9987b478219075c3af5b52d0dba3cc127294e9aae21708c0448f45eacdce4ea6
|
|
| MD5 |
82cc1bbb3bfeedc1873012a5a7bf64d8
|
|
| BLAKE2b-256 |
1ba496d9e95748470c8c25391d3470a02b61ed804fc49cb4e97fc662a7f5d70d
|