Architecture Overview¶
Design Principles¶
-
Framework-agnostic core -- All authentication logic lives in
neozen.core, with no framework imports. Framework-specific code lives inneozen.ext. -
Protocol-based -- Components depend on protocols (interfaces), not implementations. Storage, email sending, password hashing are all pluggable.
-
Functional core / imperative shell -- Pure logic in the core, I/O at the edges. Factors, policies, and validators are stateless functions operating on data.
-
Frozen dataclasses -- Configuration and models use
@dataclass(frozen=True)for immutability.
Package Structure¶
src/neozen/
├── core/ # Framework-agnostic core
│ ├── factors/ # Password, TOTP, WebAuthn, Magic Link
│ ├── identifiers/ # Email, Username, Phone
│ ├── session/ # Session management
│ ├── authz/ # RBAC, permissions, policies
│ ├── oauth/ # OAuth 2.1 server
│ ├── oauth_client/ # Social login (Google, GitHub)
│ ├── email/ # Email sender protocol + implementations
│ ├── security/ # Rate limiting, account lockout
│ ├── audit/ # Audit logging
│ ├── events/ # Event bus
│ ├── recovery/ # Password reset
│ ├── verification/ # Email verification
│ └── crypto.py # Token generation, HMAC hashing
├── storage/
│ └── sqlalchemy/ # SQLAlchemy repositories + models
├── ext/
│ ├── flask/ # Flask extension
│ ├── starlette/ # Starlette middleware
│ └── litestar/ # Litestar plugin
├── admin/ # Admin console (services + UI)
└── cli/ # Command-line interface
Data Flow¶
Request ──> Framework Extension ──> Core Factor ──> Storage
│ │ │
│ ▼ │
│ Verify / Create │
│ │ │
◀────────────────────◀───────────────┘
│
Response (session token, redirect, etc.)
Key Abstractions¶
RepositoryProtocol¶
All storage operations go through protocols:
class ReadableRepositoryProtocol[Model](Protocol):
async def get_one_by(self, **filters) -> Model: ...
async def get_many_by(self, **filters) -> list[Model]: ...
class WritableRepositoryProtocol[Model](Protocol):
async def create(self, **data) -> Model: ...
async def update_obj(self, obj, **data) -> Model: ...
class RepositoryProtocol[Model](
ReadableRepositoryProtocol[Model],
WritableRepositoryProtocol[Model],
): ...
FactorProtocol¶
Authentication methods implement one of three protocols:
AuthenticatingFactorProtocol-- single-step (password)ChallengingFactorProtocol-- two-step (WebAuthn, magic link)EnrollableFactorProtocol-- requires setup (TOTP)
See Factor Protocols for details.
EmailSenderProtocol¶
Implementations: ConsoleEmailSender (dev), SMTPEmailSender (prod).
Token Format¶
All tokens follow a GitHub-inspired format:
- 37 random characters (base62)
- 6-character CRC32 checksum
- Prefix identifying the token type
| Prefix | Purpose |
|---|---|
nz_session_ |
Session token |
nz_ev_ |
Email verification |
nz_ml_ |
Magic link |
nz_pr_ |
Password reset |
nz_at_ |
OAuth access token |
nz_rt_ |
OAuth refresh token |
Only the HMAC-SHA256 hash is stored in the database.
Roadmap¶
Planned for later 0.x releases:
- SAML 2.0 service provider
- Approval workflows
- Temporal RBAC and just-in-time elevation
- OIDC and SCIM endpoints mounted into
neozen serve(the library supports both today)
Planned for a future major version: multi-tenancy, and a SAML 2.0 identity provider.