Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

epok-auth

FastAPI-first authentication with PostgreSQL-authoritative, revocable sessions.

epok-auth is designed for private B2B web applications that need secure local accounts without rebuilding password handling, session rotation, revocation, CSRF protection, administration, and FastAPI dependencies for every product.

Status: 0.1.0b1 beta candidate. The standalone library gate is green. Colors integration and application-level parity remain required before using this beta in that product. Public APIs may still change before 1.0.

Practical testing: see the Spanish step-by-step guide in docs/USAGE_ES.md.

Validated beta gate

The clean beta tree is continuously validated by GitHub Actions. The current candidate has passed:

Gate Evidence
Functional and adversarial tests 101/101 passing
Branch coverage 94.80%
Python compatibility 3.12, 3.13 and 3.14
PostgreSQL PostgreSQL 17 migration, zero Alembic drift, integration and concurrency tests
Static quality Ruff formatting/lint/security rules and Pyright strict on production source
Dependencies Reproducible uv.lock and pip-audit
Distribution Wheel and sdist build, packaged migrations, py.typed, isolated install and CLI smoke test
Code scanning CodeQL security-extended

The repository does not claim that vulnerabilities are impossible. The green gate establishes reproducible evidence for the defined beta threat model and invariants.

What the beta includes

  • Argon2id password hashing through pwdlib, with rehash support and dummy verification;
  • local users, active/disabled state, roles, scopes, administrative provisioning and reset;
  • short-lived access JWTs with strict issuer, audience, algorithm, type and time validation;
  • opaque refresh credentials stored only as SHA-256 hashes;
  • refresh rotation, session families and reuse detection;
  • immediate access revocation through authoritative PostgreSQL session state;
  • inactivity and absolute session deadlines;
  • secure cookies, CSRF correlation and strict Origin allowlists;
  • account lockout, uniform login failures and security-event persistence;
  • plug-and-play FastAPI routers and dependencies;
  • packaged Alembic migrations and an operational CLI;
  • a Nuxt/Nitro BFF reference where Vue never receives access or refresh tokens.

Google OIDC, TOTP/MFA, passkeys, Redis coordination, multi-tenancy and service-to-service authentication remain outside this beta. See ROADMAP.md.

Installation

Until the beta is published to PyPI, consume the reviewed commit or Git tag explicitly. After publication:

uv add "epok-auth[postgres]"

Generate a secret and configure the application:

uv run epok-auth generate-secret
EPOK_AUTH_ENVIRONMENT=production
EPOK_AUTH_DATABASE_URL=postgresql://colors:password@postgres/colors
EPOK_AUTH_JWT_SECRET=<generated-secret>
EPOK_AUTH_ISSUER=colors-auth
EPOK_AUTH_AUDIENCE=colors-api
EPOK_AUTH_TRUSTED_ORIGINS=https://colors.example.com

Production configuration is fail-closed: weak secrets, insecure cookies, generic issuer/audience values, missing PostgreSQL, and ambiguous origins prevent startup.

Publication

The version has one source of truth in pyproject.toml and is exposed at runtime through importlib.metadata:

uv version --short
uv version --bump beta
uv version --bump stable
uv version --bump patch

Local PyPI credentials belong in an ignored .env.secret file. Validate or publish only from a clean main checkout:

cp .env.secret.example .env.secret
bash scripts/publish.sh --dry-run
bash scripts/publish.sh

The script runs the release checks, builds with uv build --no-sources, installs the wheel in an isolated environment and asks for the exact version before uploading. See docs/PUBLISHING.md for the complete procedure.

Database and initial administrator

uv run epok-auth check-config
uv run epok-auth upgrade-db
uv run epok-auth check-db
uv run epok-auth create-admin

The first administrator is serialized transactionally. A second initial-admin creation attempt fails rather than racing.

FastAPI integration

from fastapi import Depends, FastAPI

from epok_auth import AuthSettings, EpokAuth, Principal

settings = AuthSettings()
auth = EpokAuth.postgres(settings=settings)

app = FastAPI()
auth.install(
    app,
    prefix="/api/v1/auth",
    include_admin=True,
)

catalog = auth.protected_router(prefix="/api/v1/catalog")


@catalog.get("")
async def get_catalog(
    principal: Principal = Depends(auth.authenticated),
) -> dict[str, str]:
    return {"viewer": principal.email}


@catalog.post("")
async def update_catalog(
    principal: Principal = Depends(auth.require_scopes("catalog:write")),
) -> dict[str, str]:
    return {"editor": principal.email}


app.include_router(catalog)

auth.install() exposes:

POST /api/v1/auth/login
POST /api/v1/auth/refresh
POST /api/v1/auth/logout
POST /api/v1/auth/change-password
GET  /api/v1/auth/me

With include_admin=True it also exposes protected user administration under /api/v1/auth/users.

Application boundary

epok-auth owns authentication capabilities:

  • credentials and account state;
  • sessions, rotation and revocation;
  • generic roles/scopes;
  • browser transport protections;
  • authentication audit events.

The consuming product still owns:

  • tenants and memberships;
  • domain permissions;
  • resource-level authorization;
  • business profiles and data;
  • frontend UI and infrastructure.

A role named editor has no meaning until Colors decides what an editor can do.

Nuxt BFF

The BFF is not implemented inside the Python library. The repository includes a reference integration under examples/nuxt-bff that demonstrates this boundary:

Browser ── HttpOnly opaque session cookie ──> Nuxt/Nitro
Nuxt/Nitro ── protected access/refresh ──> FastAPI + epok-auth

Vue receives only safe user/session state. Access and refresh credentials remain server-side.

Documentation

Security model

The beta is designed around these invariants:

  • knowledge of the source code does not grant access;
  • PostgreSQL is the authority for session validity;
  • refresh credentials are one-time, opaque and hashed at rest;
  • replay revokes the whole session family;
  • changing a password, disabling or locking a user revokes sessions;
  • unsafe production configuration fails before serving traffic;
  • authentication errors do not echo secrets or distinguish unknown users.

Development

uv sync --locked --all-extras --group dev
uv run ruff format --check .
uv run ruff check .
uv run pyright
uv run pytest

Pull requests must pass the GitHub Actions CI / merge-gate, including PostgreSQL 17, Python 3.12–3.14, branch coverage, dependency auditing, packaging and isolated installation. CodeQL must also pass.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

epok_auth-0.1.0b1.tar.gz (131.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

epok_auth-0.1.0b1-py3-none-any.whl (38.3 kB view details)

Uploaded Python 3

File details

Details for the file epok_auth-0.1.0b1.tar.gz.

File metadata

  • Download URL: epok_auth-0.1.0b1.tar.gz
  • Upload date:
  • Size: 131.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for epok_auth-0.1.0b1.tar.gz
Algorithm Hash digest
SHA256 d46d62063a0f9353c74cd99f5c591a0cc50009a9569c47065b7068e305f902d5
MD5 88837fddad1f0b13f702dcb0ab199340
BLAKE2b-256 faed980c26d0401dd045f6f033b8fe49bea6e31d9189301b34b75a63057fd138

See more details on using hashes here.

File details

Details for the file epok_auth-0.1.0b1-py3-none-any.whl.

File metadata

  • Download URL: epok_auth-0.1.0b1-py3-none-any.whl
  • Upload date:
  • Size: 38.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.12.1 {"installer":{"name":"uv","version":"0.12.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for epok_auth-0.1.0b1-py3-none-any.whl
Algorithm Hash digest
SHA256 7d07ebeee28107190ae938ef589c34e044f7ee11f107e5d067eeac03b9f50fd2
MD5 7a85f2f38e886af3b2d6359b7761b003
BLAKE2b-256 2e0b354a1567d8320797374673d0fd6026938c0dbe3fcdf97a5e953e3c8f7937

See more details on using hashes here.

Release history Release notifications | RSS feed

0.6.0

2 files

0.5.0

2 files

0.4.1

2 files

0.4.0

2 files

0.3.0

2 files

0.2.1

2 files

0.2.0

2 files

0.1.0

2 files

This release

0.1.0b1 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page