regstack

Production-grade user accounts for your FastAPI app — without the vendor lock-in, the second service to run, or the homegrown auth bugs.

pip install regstack, point it at SQLite (default), PostgreSQL, or MongoDB, and you have register / login / verify-email / reset-password / change-email / delete-account / optional SMS two-factor / admin endpoints / themeable HTML pages — all behind a small Python API and one config file.

The problem regstack solves

Every web application that has users eventually needs the same dozen endpoints: register, log in, log out, verify email, reset a forgotten password, change password, change email, delete account, list users for the admin panel, lock out brute-force attackers, and ideally a second factor. Every one of those endpoints has a well-known way to get subtly wrong:

  • Password hashing. Use Argon2id, not MD5, SHA-1, bcrypt-without-pepper, or — somehow still common — plain text.

  • Token revocation. A JWT is signed and self-contained: the server can’t “log it out” unless you build a revocation list. Forget this and a stolen token works until it expires.

  • Account enumeration. A login or password-reset endpoint that responds differently for “user exists” vs “user doesn’t” lets an attacker harvest your customer list.

  • Bulk session invalidation. When a user changes their password because they think they were compromised, every existing token they hold should stop working immediately. Most homegrown JWT layers don’t do this.

  • One-time tokens. Verification and password-reset tokens should be random, hashed at rest, single-use, and expire fast. Storing the raw token in the database is a “now your DB backup is also a credential dump” mistake.

  • Phone numbers. SMS codes need E.164-validated numbers, attempt limits, and an upstream provider. Wiring all of that yourself for a single feature is rarely worth it.

Doing all of these correctly, with tests, is two to four weeks of engineering for a competent team. Doing them once and embedding the result everywhere is what regstack is for.

Why not just use…?

There are real alternatives. Here’s why regstack might still be the right call.

Alternative

Why you might pick it

Why you might pick regstack instead

Auth0 / Clerk / WorkOS / Stytch (hosted SaaS)

Zero ops. Polished UI. Enterprise SSO out of the box.

Cost scales per-user. Your auth lives on someone else’s servers. Your customer list is in their database. Vendor lock-in is real and migrations are painful.

Keycloak / Authentik / Authelia / Ory Kratos (self-hosted IAM)

Full identity platform. SAML, OIDC, federation.

A separate Java/Go service to run, monitor, back up, upgrade, and reason about. Heavyweight for “let users sign up”. Schema lives outside your app.

fastapi-users

Same language, same framework. Good registration / login primitives.

Doesn’t ship verification flows, anti-enumeration, bulk revoke, SMS MFA, admin endpoints, or themeable pages — you build those. regstack is the longer tail.

Roll your own

Total control. No dependency to learn.

You re-solve every bullet from “The problem” above, including the ones you didn’t know existed yet. Two to four engineering weeks, then forever to maintain.

regstack’s bet is that for most FastAPI apps the right answer is embed a small Python library that owns the boring 80% correctly, and keep the user table in your own database — not “stand up a separate auth product” and not “write the boring 80% from scratch each time”.

What’s distinctive about regstack

  • Native pywebview setup tools, not just Click prompts.

    • regstack oauth setup opens a real desktop window that walks an operator through registering a Google OAuth 2.0 client and merging the credentials into regstack.toml non-clobberingly — no copy-pasting the redirect URI four times.

    • regstack theme design opens a live theme designer with a real-time preview of the SSR auth pages: tweak a colour, see the Sign-in card update on the right; click Save to write regstack-theme.css. CSS-only re-skin in minutes, no template editing required. Both tools are local-only (127.0.0.1 + per-launch token), have a --headless mode for headless CI (plus --dry-run for no-write validation), and ship under the same test-from-the-outside Playwright suite the SSR pages do.

  • Zero vendor lock-in. Your user table is in your database, not someone else’s. Switch storage backends by changing one URL.

  • Opt-in everything. No SMS extra → no twilio / aioboto3 install. No SES → no AWS SDK. No SSR → no Jinja templates loaded. The base install is small.

About the examples

To keep URLs and config values consistent across the docs, every example pretends to embed regstack into a fictional app hosted at app.example.com. Throughout the docs:

What

Value

Public host

app.example.com

base_url

https://app.example.com

Database host (prod)

dbhost.example.com

Database user

<username>

Database password

<password>

Database name

dbname

Email sender

noreply@app.example.com

Local dev port

localhost:8000

So a Postgres URL looks like postgresql+asyncpg://<username>:<password>@dbhost.example.com:5432/dbname, a MongoDB URL like mongodb://<username>:<password>@dbhost.example.com:27017/dbname, and the local SQLite path sqlite+aiosqlite:///./dbname.db. Substitute your own values when copying — the shape is the only thing that matters.

What’s in the box

  • Three storage backends, one API. SQLite (the default — single file, no server), Postgres (via asyncpg), MongoDB (via pymongo). Same routers, same hooks; switch by changing the database_url.

  • JSON API. Register, verify email, resend verification, log in (with optional SMS second step), log out, me, change password, change email + confirm, forgot/reset password, delete account, admin endpoints.

  • Server-rendered HTML pages (opt-in). Login, register, verify, forgot, reset, MFA confirm, account dashboard. Themed via CSS custom properties — no template editing required for a re-skin. Full template overrides are still possible per host.

  • CLIs + native pywebview tools. regstack init (interactive project bootstrap), regstack oauth setup (guided Google OAuth client configuration in a native webview — see OAuth guide), regstack theme design (live theme designer with a real-time preview of the SSR widgets — see theming guide), regstack ses setup (guided SES email backend configuration that validates against AWS, new in 0.8.0), regstack create-admin, regstack doctor, regstack migrate (Alembic schema migrations for SQL backends), regstack validate (end-to-end probe of a deployed install). Every CLI command is documented under CLI reference.

  • OAuth — Sign in with Google (opt-in, since 0.3.0). Authorization Code with PKCE, ID-token verification, identity-linking with a default-refuse policy hosts can opt out of. Connected-accounts panel on the SSR /account/me page. See the OAuth guide.

  • Pluggable email and SMS. Email backends: console (dev), SMTP, Amazon SES. SMS backends: Amazon SNS, Twilio. Plug your own in by implementing one method.

  • Security defaults you would otherwise have to research. Argon2id password hashing, per-purpose JWT signing keys, per-token revocation, bulk session invalidation on password change, login lockout with HTTP 429 + Retry-After, durable hashed verification tokens, 6-digit SMS codes with attempt limits, anti-enumeration on forgot/resend endpoints, CSP-friendly templates with no inline styles.

Where to next

  • New here? Start with the Quickstart — install, generate a config, register a user end-to-end.

  • Embedding regstack in an existing app? Read Embedding for the patterns most hosts adopt (custom email, hooks, multiple regstacks, theming).

  • Curious how it’s put together internally? See Architecture.

  • Designing a deployment? The Security model page is the threat model, the JWT scheme, and the things you still own as a host.

Project status

Alpha. Latest tagged release: v0.5.0. SQLite is the default and runs with no infrastructure; PostgreSQL and MongoDB pass the same parametrized integration suite. The full backend matrix runs in parallel against every test, so a green CI on main is a strong correctness signal.