user-registration
A typed, framework-agnostic, and database-agnostic user registration package for Python applications.
user-registration provides the core domain and application services required to register users while keeping HTTP frameworks, databases, ORM implementations, and application infrastructure outside the core package.
Why user-registration?
The package separates registration business logic from infrastructure.
Application
|
v
+----------------------+
| RegistrationService |
+----------+-----------+
|
+--------------+--------------+
| | |
v v v
Validation Password Repository
Registry Hasher Protocol
|
v
Argon2
The core package does not require FastAPI, Django, Flask, SQLAlchemy, PostgreSQL, MySQL, MongoDB, or another infrastructure technology.
Features
- Python 3.12+
- Fully typed public API
- Framework independent
- Database independent
- Configurable registration behavior
- Username validation
- Email validation
- Extensible validation registry
- Password policy integration with
password-validator-s - Argon2 password hashing
- Repository abstraction
- Duplicate-user detection
- Registration hooks
- Environment-based configuration
- Unit and integration testing
mypystrict type checking- Ruff linting and formatting
Packages
The project is distributed as three packages.
| Package | Purpose |
|---|---|
user-registration |
Framework- and database-independent registration core |
user-registration-fastapi |
FastAPI HTTP adapter |
user-registration-sqlalchemy |
SQLAlchemy repository adapter |
The core package can be used independently of either adapter.
Installation
Core package
pip install user-registration
FastAPI Integration
pip install user-registration-fastapi
The FastAPI adapter automatically installs the core package and FastAPI.
SQLAlchemy Integration
pip install user-registration-sqlalchemy
The SQLAlchemy adapter automatically installs the core package and SQLAlchemy.
Full FastAPI + SQLAlchemy stack
pip install user-registration-fastapi user-registration-sqlalchemy
Basic Usage
The core package expects the application to provide a repository implementation.
from user_registration import (
Argon2Hasher,
PasswordValidatorAdapter,
RegistrationConfig,
RegistrationRequest,
RegistrationService,
)
service = RegistrationService(
repository=repository,
password_hasher=Argon2Hasher(),
password_validator=PasswordValidatorAdapter(),
config=RegistrationConfig(),
)
result = service.register(
RegistrationRequest(
username="test",
email="test@example.com",
password="StrongPassword123!",
)
)
if result.success:
print(f"Registered user: {result.user_id}")
else:
print(result.status)
print(result.errors)
The application supplies the repository implementation.
For example:
RegistrationService
|
v
UserRepository
|
+---- In-memory repository
+---- SQLAlchemy repository
+---- PostgreSQL repository
+---- MongoDB repository
+---- Custom application repository
Public API
from user_registration import (
Argon2Config,
Argon2Hasher,
ConfigurationError,
DuplicateUserError,
EmailValidator,
FieldValidator,
NoOpRegistrationHook,
PasswordHasher,
PasswordPolicyValidator,
PasswordValidatorAdapter,
RegistrationConfig,
RegistrationError,
RegistrationHook,
RegistrationHookError,
RegistrationPersistenceError,
RegistrationRequest,
RegistrationResult,
RegistrationService,
RegistrationStatus,
User,
UserAlreadyExistsError,
UserRepository,
ValidationError,
ValidationRegistry,
UsernameValidator,
create_default_validation_registry,
generate_token,
)
Applications should prefer these public imports rather than importing internal modules.
Registration Lifecycle
A registration request follows this general flow:
RegistrationRequest
|
v
Required-field validation
|
v
Normalization
|
v
Field validation
|
v
Duplicate checks
|
v
Password policy validation
|
v
Password hashing
|
v
User creation
|
v
Repository persistence
|
v
Registration hooks
|
v
RegistrationResult
FastAPI
Install
pip install user-registration-fastapi
Then include the router:
from fastapi import FastAPI
from user_registration_fastapi import router
app = FastAPI()
app.include_router(router)
The adapter exposes:
POST /users/register
Request:
{
"username": "test",
"email": "test@example.com",
"password": "StrongPassword123!"
}
Successful response:
{
"user_id": "..."
}
HTTP Behavior:
| Condition | Status |
|---|---|
| Successful registration | 201 Created |
| Validation failure | 422 Unprocessable Entity |
| Duplicate user | 409 Conflict |
| Persistence failure | 500 Internal Server Error |
The application supplies the RegistrationService through dependency injection. |
See docs/fastapi.md
SQLAlchemy
Install:
pip install user-registration-sqlalchemy
The adapter implements the core repository contract using SQLAlchemy 2.x
from user_registration_sqlalchemy import SQLAlchemyUserRepository
repository = SQLAlchemyUserRepository(session)
The application remains responsible for:
- engine configuration
- session lifecycle
- transaction management
- migrations
- database configuration
Configuration
Registration behavior can be configured directlyL
from user_registration import RegistrationConfig
config = RegistrationConfig(
username_min_length=4,
username_max_length=50,
email_required=True,
username_required=True,
password_required=True,
normalize_email=True,
normalize_username=True,
)
Environment variables are also supported:
USER_REGISTRATION_USERNAME_MIN_LENGTH
USER_REGISTRATION_USERNAME_MAX_LENGTH
USER_REGISTRATION_EMAIL_REQUIRED
USER_REGISTRATION_USERNAME_REQUIRED
USER_REGISTRATION_PASSWORD_REQUIRED
USER_REGISTRATION_NORMALIZE_EMAIL
USER_REGISTRATION_NORMALIZE_USERNAME
Password Security
Passwords are validated and hashed using Argon2 before persistence.
The package does not store plaintext passwords.
Security-sensitive tokens use Python's secrets module.
Applications should never log plaintext passwords, password hashes, registration requests containing passwords, or security tokens.
The package intentionally does not implement authentication, authorization, rate limiting, MFA, or account lockout. Those concerns belong in the application or authentication layer.
The registration service uses the configured PasswordHasher implementation.
The default implementation is based on Argon2:
from user_registration import Argon2Hasher
hasher = Argon2Hasher()
password_hash = hasher.hash("StrongPassword123!")
assert hasher.verify(
"StrongPassword123!",
password_hash,
)
Password policy validation is provided through the PasswordPolicyValidator abstraction.
Extensibility
The package is designed around protocols and dependency injection
Repository
class UserRepository(Protocol):
...
Applications can provide their own repository implementation.
Password hasher
class PasswordHasher(Protocol):
...
Applications can provide a different password hashing implementation.
Field validation
Custom validators can be registered:
class ReservedUsernameValidator:
def validate(self, value: str) -> str | None:
if value == "admin":
return "Username is reserved"
return None
Registration hooks
Applications can register hooks that execute after successful registration
See docs/hooks.md
Explicitly out of scope
- Login
- Sessions
- JWT authentication
- 0Auth/OIDC
- MFA
- RBAC
- Password reset
- Account recovery
- Email delivery
- ORM models
- Database connections
- HTTP routing
These concerns belong to the application or separate integration.
Development
Clone the repository:
git clone https://github.com/ShamimurRahmanShuvo/user_registration.git
cd user_registration
Create a virtual environment:
python3.14 -m venv .venv
Install development dependencies:
.venv/bin/python -m pip install -e ".[dev]"
Run tests:
.venv/bin/python -m pytest -v
Run type checking:
.venv/bin/python -m mypy src
Run linting:
.venv/bin/python -m ruff check src tests
Check formatting:
.venv/bin/python -m ruff format --check src tests
Build the package:
.venv/bin/python -m build
Documentation
Detailed documentation is available in docs/
- Architecture
- API Contract
- Configuration
- Repositories
- Validation
- Password Security
- Registration Hooks
- FastAPI Integration
- SQLAlchemy Integration
- Testing
- Release Guide
Versioning
The project follows semantic versioning.
During the 0.x development series, public APIs may change between minor releases.
The 1.0.0 release will mark the first stable public API contract
See CHANGELOG.md for release history.
License
MIT License
See LICENSE
Project Links
Metadata
Release files for user-registration 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| user_registration-1.0.0.tar.gz | 45.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| user_registration-1.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 67.0 kB
Release files / user_registration-1.0.0.tar.gz
| Download URL | user_registration-1.0.0.tar.gz |
|---|---|
| Size | 45.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
307b853b05dc2e85d514dfee20821c79afab7ff8f0c667951e2a3837a0c09693
|
|
BLAKE2b-256 checksum How to use checksums |
cb4e46a79d2c62d510336e081da7aed536c1da0f43387df7be7b79a35073657e
|
| 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 1, 2026.
Transparency logRelease files / user_registration-1.0.0-py3-none-any.whl
| Download URL | user_registration-1.0.0-py3-none-any.whl |
|---|---|
| Size | 21.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2ee92a7d283d5dbee954e2b5dd8d5b638a3441fc879ee2597475605cd6269d27
|
|
BLAKE2b-256 checksum How to use checksums |
80b4a7d1ec2ee25db69d44e3763eb95f0c4c26e6e2673edf45c2dde991a0d04a
|
| 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 1, 2026.
Transparency log