This release is a pre-release and may not be stable for production use.
OutlabsAuth
Library-first authentication and authorization for FastAPI — RBAC, optional ABAC, API keys, and Postgres-backed permissions that live inside your app.
Alpha release - packaged on PyPI; the public API is still settling before 1.0.
Why OutlabsAuth
Most auth products push you into a separate IdP or a black-box service. OutlabsAuth is the opposite: a Python library you mount into your FastAPI app, with your Postgres, your routes, and your deployment.
| You get | Details |
|---|---|
| Two presets | SimpleRBAC (flat roles) or EnterpriseRBAC (entity hierarchy + tree permissions) |
| Auth surface | JWT access/refresh, API keys, service tokens, invitations, optional OAuth / magic link / access codes |
| Admin console | Optional sister app OutlabsAuth UI — point it at any host that mounts this library |
| Ops | Packaged Alembic migrations, CLI bootstrap, Redis when needed, optional in-process permission cache (cache_backend="memory") |
Documentation
Implementers start in the OutlabsAuth Handbook
(docs-library/) — human-readable guides written for people integrating the
library. A Nuxt docs site lives beside this repo at
../outlabsAuth-docs (Nuxt UI docs template); re-port
with python3 scripts/port_handbook.py from that project.
| Guide | What it covers |
|---|---|
| Handbook home | Reading paths, full guide index |
| Introduction | Mental model in a few minutes |
| Getting Started | Install → migrate → mount → login → optional UI |
| Choosing a Preset | SimpleRBAC vs EnterpriseRBAC in plain language |
| Routers & Prefixes | Which get_*_router factories to mount |
| Configuration | Constructor flags, Redis, schema, production defaults |
| Background Maintenance | Typed one-shot cleanup/sync, external ownership, activation, and rollback |
| OAuth · Sessions & audit · Passwordless | Optional auth extensions |
| Examples | Runnable SimpleRBAC + EnterpriseRBAC apps |
| OutlabsAuth UI | Sister admin console (Nuxt static SPA) |
Maintainers (design decisions, audits, release process): docs/.
Proposed, awaiting review: Tenant identities and delegated administration
and its independent review packet. These are
design documents; scoped identities and persistent administrative grants are not
activated by this draft.
S1 security release: S1 implementation receipt records all eight baseline fixes, migration safety, recovery fencing and their regressions. The a37 independent review and qualification receipt record the acceptance boundaries; consumer adoption requires its own package, migration and staging gates.
Deep host DX / feature matrix when you need them: API design, Comparison matrix.
Choose a Preset
Need departments / teams / org tree?
NO → SimpleRBAC
YES → EnterpriseRBAC
| Need | Preset |
|---|---|
| Flat users → roles → permissions | SimpleRBAC |
| Hierarchy, memberships, tree permissions | EnterpriseRBAC |
Install
pip install outlabs-auth
You need PostgreSQL. Provide at least:
- a
postgresql+asyncpg://...URL - a JWT
secret_key(≥ 32 characters for HS256)
Quickstart
import os
from contextlib import asynccontextmanager
from fastapi import FastAPI
from outlabs_auth import SimpleRBAC
from outlabs_auth.routers import get_auth_router
auth = SimpleRBAC(
database_url="postgresql+asyncpg://postgres:postgres@localhost:5432/app",
# Must be at least 32 characters when signing with HS256, or construction
# fails. Generate one with:
# python -c "import secrets; print(secrets.token_urlsafe(48))"
secret_key=os.environ["SECRET_KEY"],
)
# Builds the engine, services and dependencies synchronously. Required *before*
# any router factory runs: they dereference `auth.deps`, which otherwise only
# exists after `initialize()` — and that's async, so it cannot run at import.
auth.prime_fastapi_routing()
@asynccontextmanager
async def lifespan(app: FastAPI):
await auth.initialize() # async work: migrations, Redis, service wiring
yield
await auth.shutdown()
app = FastAPI(lifespan=lifespan)
# Installs the exception handlers *and* the UnitOfWork/RequestCache middleware.
# Prefer this over bare register_exception_handlers(): the middleware commits
# before the response is sent, which is what makes a create immediately readable.
auth.instrument_fastapi(app)
app.include_router(get_auth_router(auth, prefix="/auth"))
tests/unit/test_readme_quickstart.py executes this block, so it cannot rot.
Deliberate details:
prime_fastapi_routing()before mounting — otherwiseConfigurationError: Dependencies not initialized- Real
secret_key— placeholders under 32 characters fail at construction under HS256
You can also mount inside lifespan() after initialize() (no priming) — see examples/simple_rbac/main.py.
For production, run migrations with the CLI (auto_migrate=False). Continue with Getting Started and Configuration.
OutlabsAuth UI
Optional sister repository: a Nuxt 4 + Nuxt UI static single-page admin console that plugs into any app hosting this library. Each deployment names its API in a runtime app-config.json; the console reads public feature flags from GET {authApiPrefix}/auth/config, then loads the permission catalog from authenticated GET {authApiPrefix}/auth/config/permissions when needed.
# Terminal 1 — Enterprise example API
cd examples/enterprise_rbac
uv sync && uv run outlabs-auth migrate && uv run python reset_test_env.py
uv run uvicorn main:app --reload --port 8004
# Terminal 2 — from the outlabsAuth repo root (Bun 1.3.3+, Node.js 22.18+)
cd ../OutlabsAuthUI # https://github.com/outlabsio/OutlabsAuthUI
bun install
cp public/app-config.template.json public/app-config.json
# the template already targets this example: http://localhost:8004, /v1, frontendProfileKey console
bun run dev # http://localhost:3000
Open http://localhost:3000 and sign in with a seeded admin (e.g. admin@acme.com / Testpass1!). Full wiring, production hosting and the console's release gate: docs/AUTH_UI.md.
CLI Operations and Administration
The CLI has two operating planes: local database lifecycle commands and authenticated administration through a mounted OutlabsAuth API. The optional admin UI is not required for CLI workflows.
Local database lifecycle
export DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/app
# optional: export OUTLABS_AUTH_SCHEMA=outlabs_auth
outlabs-auth migrate
outlabs-auth seed-system
printf '%s\n' "$INITIAL_ADMIN_PASSWORD" | \
outlabs-auth bootstrap-admin --email admin@example.com --password-stdin
Useful operators: outlabs-auth doctor (read-only preflight) and
outlabs-auth bootstrap (idempotent first-boot). Namespaced forms such as
outlabs-auth db migrate and outlabs-auth ops doctor are also available;
the original spellings remain supported.
Remote administration
Contexts contain target metadata only. Tokens are never written to the context file. Human logins use a separate, target-bound owner-only session store; unattended automation can keep using a named environment variable.
outlabs-auth context add local \
--base-url http://127.0.0.1:8004 \
--api-prefix /v1
outlabs-auth capabilities
outlabs-auth auth login --email admin@example.com # hidden password prompt
outlabs-auth auth status
outlabs-auth whoami
outlabs-auth users list --status active --all
outlabs-auth users get admin@example.com
outlabs-auth permissions explain reports:read --user admin@example.com
capabilities reports both configured feature flags and the stable names of
the OutlabsAuth router surfaces actually mounted by the host. Feature flags do
not prove that a route exists; automation should check mounted_surfaces
before selecting a remote command. Hosts can make that contract executable:
from outlabs_auth.routers import assert_auth_surfaces
assert_auth_surfaces(app, {"auth", "users", "roles", "permissions"})
An embedded API that does not expose the full login/register router can mount
get_capabilities_router(auth, prefix="/auth") alongside only the small
surfaces it needs.
The CLI also has typed lifecycle commands for self-service accounts, users, roles, permissions and ABAC policy, entities, memberships, API keys, integration principals/system keys, sessions, audit events, and entity-type configuration. References accept UUIDs or unambiguous human identifiers such as email, role name, entity slug, and API-key name.
outlabs-auth permissions create --name reports:read --display-name "Read reports"
outlabs-auth roles create \
--name report-reader --display-name "Report reader" \
--permission reports:read
outlabs-auth memberships add \
--user analyst@example.com --entity engineering \
--role report-reader --yes
outlabs-auth users access-report analyst@example.com
For unattended agents, configure a least-privilege API key instead of a human session when host policy permits it:
outlabs-auth context add production \
--base-url https://api.example.com \
--api-prefix /iam \
--credential-type api-key
export OUTLABS_AUTH_API_KEY='scoped-key-value'
To create a least-privilege key while signed in as a human, declare where its
one-time secret must go. The CLI validates the destination before creating the
key and writes it with mode 0600:
outlabs-auth api-keys grantable-scopes --entity engineering
outlabs-auth api-keys create \
--name coding-agent --scope user:read --scope permission:read \
--entity engineering --secret-file ./coding-agent.key --yes
Coding agents and scripts should select the versioned JSON contract globally:
outlabs-auth --output json --non-interactive users list --all
outlabs-auth --output json commands memberships add --shallow
Successes and failures both emit one JSON document on stdout with stable error
codes and exit categories. commands exposes the live command/option schema,
while guarded api request provides a bounded relative-path escape hatch for
new mounted endpoints.
For repeatable administration, review and save a target-bound plan before any write:
outlabs-auth --output json plan examples/cli/state.example.json --out state.plan.json
outlabs-auth --output json --non-interactive apply state.plan.json --yes
Complete user guide: Command Line.
Maintainer contract: docs/CLI_DESIGN.md.
Agent reference: docs/CLI_AGENT_GUIDE.md.
Manifest contract: docs/CLI_MANIFEST.md.
Configuration and deployment: Configuration and
docs/DEPLOYMENT_GUIDE.md.
Production Snapshot
from outlabs_auth import EnterpriseRBAC
auth = EnterpriseRBAC(
database_url="postgresql+asyncpg://user:password@db-host/app?ssl=require",
database_schema="outlabs_auth",
secret_key="replace-me-with-a-long-secret",
auto_migrate=False,
redis_url="redis://cache-host:6379/0",
background_job_mode="disabled",
)
- Prefer a direct Postgres URL over transaction-pooler endpoints for auth-heavy apps
- Migrate in a single-process prestart step; then start workers
- Mount under an app-owned prefix such as
/iam - Point OutlabsAuth UI
authApiPrefixat that same prefix - Run one external
auth.run_maintenance_once()owner; never one loop per API replica
export DATABASE_URL='postgresql+asyncpg://user:password@db-host/app?ssl=require'
export OUTLABS_AUTH_SCHEMA='outlabs_auth'
outlabs-auth migrate
outlabs-auth seed-system
exec uvicorn myapp.main:app --host 0.0.0.0 --port 8000 --workers 2
Status
Current Library Version: 0.1.0a37
Release evidence: S1 qualification and publication receipt. Package publication and consumer adoption are separate gates.
Release Stage: Alpha
License
MIT, copyright 2026 OUTLABS LLC.
Metadata
Release files for outlabs-auth 0.1.0a37
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| outlabs_auth-0.1.0a37.tar.gz | 481.8 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| outlabs_auth-0.1.0a37-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.1 MB
Release files / outlabs_auth-0.1.0a37.tar.gz
| Download URL | outlabs_auth-0.1.0a37.tar.gz |
|---|---|
| Size | 481.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1c95c04846fdda6565ce2f9e770108fc38bda625fbbc1a6ca33c1193c5a826aa
|
|
BLAKE2b-256 checksum How to use checksums |
4d49f717e1baf1995196361f3deb704f6f65a09f3c37c91758b4aa66e1b4f18a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency logRelease files / outlabs_auth-0.1.0a37-py3-none-any.whl
| Download URL | outlabs_auth-0.1.0a37-py3-none-any.whl |
|---|---|
| Size | 629.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4c557989cf318248b593a8edc913e86f3136eaa0df27bb993e84a5a9b26682e0
|
|
BLAKE2b-256 checksum How to use checksums |
aa33f9c6d2a80d64c9f9eeb03e7596560ee07a4a1760b958b7cf5d6884e417ce
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency logSecurity for outlabs-auth 0.1.0a37
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for outlabs_auth-0.1.0a37.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.