Flexible identity — sign in with a username, not just an email
The new identifier setting picks how accounts are identified: "email" (the default — existing apps are unchanged) or "username".
- Username mode:
sign_up/sign_intake ausername; the email-only flows (verification, password reset) simply go unused. The schema carries bothemailandusernameas nullable, UNIQUE columns, so an app can also collect an optional email alongside a username. - Username policy, all configurable: length bounds (
usernameMinLength/usernameMaxLength, default 3–30), an allowed-characterusernamePattern, and a reserved-name block-list (~90 names) to prevent impersonation and route collisions. Usernames are lowercase-normalised, so uniqueness is case-insensitive on every backend. - Live availability checks:
AuthService.username_available()andGET /auth/username-available?u=<name>(per-IP rate-limited; returns{available, reason?}) for as-you-type pickers. - Migration 0004 ships in SQLite, PostgreSQL, and MySQL variants; the full account lifecycle is tested against real servers.
435 tests pass, including live PostgreSQL and MariaDB backends. See the pyxle-auth docs once the 0.7.0 site deploy lands.