Summary
Prepare authsome for stateless, horizontally-scalable production deployments. The current implementation relies on local disk for KV storage and session state, which breaks in containerised/serverless environments where the filesystem is ephemeral and multiple replicas can't share state.
Motivation
- File-based storage (
DiskStore, local KV) does not persist across container restarts or scale beyond a single process.
- Session state stored in-process is lost on eviction or pod churn.
- Operators deploying to Railway, Fly.io, Render, or any container platform need a clear production path.
Scope of work
1. Dockerfile
- Multi-stage build (builder + runtime) using the
uv tool-chain.
- Non-root user, minimal image (e.g.
python:3.12-slim).
- Health-check endpoint (
GET /health).
- Expose
AUTHSOME_* env vars for all runtime config.
2. Postgres as the relational store
- Wire up the five server-owned registries (
IdentityRegistry, PrincipalRegistry, VaultRegistry, IdentityClaimRegistry, PrincipalVaultBindingRegistry) to use Postgres when AUTHSOME_DATABASE_URL starts with postgresql://.
- Ensure connection pooling is configured (e.g. via
asyncpg + SQLAlchemy async engine).
- Migration strategy (Alembic or equivalent) so schema is applied at startup.
3. Redis as session cache
- Replace any in-process or file-backed session/token cache with Redis.
- JTI replay cache (PoP auth anti-replay,
src/authsome/identity/proof.py) must use Redis with a TTL equal to the token window.
AUTHSOME_REDIS_URL controls the connection; fall back to in-memory only in test/dev mode.
4. Redis as vault backend
- Add a
RedisVaultBackend alongside the existing DiskStore backend.
- Encrypted blobs (already encrypted by
Vault) stored as Redis keys with the same vault:<vault_id>:... naming scheme.
- Backend selected via
AUTHSOME_VAULT_BACKEND=redis (default: disk for local dev).
- Master key continues to be loaded from env (
AUTHSOME_MASTER_KEY) or OS keyring; never stored in Redis.
5. Remove file-as-cache anti-patterns
- Audit the codebase for any use of temp files, local JSON caches, or in-process dicts that would break under multiple replicas.
- Replace each with Redis (for shared mutable state) or move to stateless computation.
6. Self-hosting guide (docs/guides/self-hosting.md)
- Prerequisites: Docker, a Postgres instance, a Redis instance.
- Environment variable reference (
AUTHSOME_DATABASE_URL, AUTHSOME_REDIS_URL, AUTHSOME_VAULT_BACKEND, AUTHSOME_MASTER_KEY, etc.).
- Step-by-step: pull image → set env vars →
authsome init → verify with GET /health.
- Example
docker-compose.yml for local production simulation (authsome + Postgres + Redis).
- Notes on secret management (do not put
AUTHSOME_MASTER_KEY in compose files in production; use Doppler/Vault/cloud secrets).
- Upgrade/migration instructions.
Acceptance criteria
Implementation notes
- Keep
DiskStore and SQLite paths working for local dev — operators should be able to run authsome init without any external services.
- Backend selection should be via env vars, not code changes.
- Do not introduce Redis or Postgres as hard dependencies for the base install; use optional extras (
authsome[redis], authsome[postgres]).
- Follow existing engineering principles: YAGNI, deep modules, no premature abstraction.
References
- Architecture overview:
CLAUDE.md → Architecture section
- Current store:
src/authsome/server/store/repositories.py
- PoP auth / JTI cache:
src/authsome/identity/proof.py
- Vault backend:
src/authsome/vault/
- ServerSettings:
src/authsome/server/settings.py
- Existing self-hosting stub:
docs/guides/self-hosting.md
Summary
Prepare authsome for stateless, horizontally-scalable production deployments. The current implementation relies on local disk for KV storage and session state, which breaks in containerised/serverless environments where the filesystem is ephemeral and multiple replicas can't share state.
Motivation
DiskStore, local KV) does not persist across container restarts or scale beyond a single process.Scope of work
1. Dockerfile
uvtool-chain.python:3.12-slim).GET /health).AUTHSOME_*env vars for all runtime config.2. Postgres as the relational store
IdentityRegistry,PrincipalRegistry,VaultRegistry,IdentityClaimRegistry,PrincipalVaultBindingRegistry) to use Postgres whenAUTHSOME_DATABASE_URLstarts withpostgresql://.asyncpg+ SQLAlchemy async engine).3. Redis as session cache
src/authsome/identity/proof.py) must use Redis with a TTL equal to the token window.AUTHSOME_REDIS_URLcontrols the connection; fall back to in-memory only in test/dev mode.4. Redis as vault backend
RedisVaultBackendalongside the existingDiskStorebackend.Vault) stored as Redis keys with the samevault:<vault_id>:...naming scheme.AUTHSOME_VAULT_BACKEND=redis(default:diskfor local dev).AUTHSOME_MASTER_KEY) or OS keyring; never stored in Redis.5. Remove file-as-cache anti-patterns
6. Self-hosting guide (
docs/guides/self-hosting.md)AUTHSOME_DATABASE_URL,AUTHSOME_REDIS_URL,AUTHSOME_VAULT_BACKEND,AUTHSOME_MASTER_KEY, etc.).authsome init→ verify withGET /health.docker-compose.ymlfor local production simulation (authsome + Postgres + Redis).AUTHSOME_MASTER_KEYin compose files in production; use Doppler/Vault/cloud secrets).Acceptance criteria
docker buildproduces a working image;docker runwith env vars starts the daemon cleanly.AUTHSOME_DATABASE_URLis set.AUTHSOME_VAULT_BACKEND=redis; encrypted at rest.docs/guides/self-hosting.mdis complete, including a workingdocker-compose.ymlexample.uv run pytestpasses (new integration tests for Redis/Postgres backends, gated behind optional deps or docker fixtures).uv run ruff checkanduv run ty checkpass.Implementation notes
DiskStoreand SQLite paths working for local dev — operators should be able to runauthsome initwithout any external services.authsome[redis],authsome[postgres]).References
CLAUDE.md→ Architecture sectionsrc/authsome/server/store/repositories.pysrc/authsome/identity/proof.pysrc/authsome/vault/src/authsome/server/settings.pydocs/guides/self-hosting.md