3.1 KiB
3.1 KiB
Authentication Services — Design Document
For Claude: This document captures design decisions for the authentication service layer. The implementation plan is at
docs/plans/2026-02-13-auth-services-plan.md.
Scope
Backend-only authentication services. No HTTP routes or templates in this phase.
Three independent services:
- PasswordService — Argon2 hash/verify
- WebAuthnService — FIDO2 registration/authentication via python-fido2
- MagicLinkService — Invite token create/validate
Design Decisions
1. PasswordService (stateless, pure crypto)
- Wraps
argon2-cffiPasswordHasher - Two methods:
hash(password) -> str,verify(hash, password) -> bool PasswordHasherinjected via constructor for testability- No repository dependency — caller reads/writes credentials
- Uses argon2-cffi OWASP-recommended defaults
verify()returnsbool(catchesVerifyMismatchErrorinternally)
2. WebAuthnService (class wrapping Fido2Server)
- Constructor takes
rp_id,rp_name,origin— createsFido2Serverinternally - Four methods:
begin_registration,complete_registration,begin_authentication,complete_authentication begin_*methods return(options, state)— caller stores state (e.g., in HTTP session)complete_*methods accept state back from caller- No repository dependency — caller handles credential CRUD
- Uses python-fido2 v2.1 API (
Fido2Server,PublicKeyCredentialRpEntity, etc.)
3. MagicLinkService (token lifecycle)
- Depends on
MagicLinkRepository(injected) create(username, created_by?, note?) -> MagicLink— generates token viasecrets.token_urlsafe(32)validate(token) -> MagicLink | None— checks exists, not used, not expiredmark_used(token) -> bool— delegates to repocleanup_expired() -> int— delegates to repo- TTL configurable via constructor (from
Settings.invite_ttl)
4. Testing Strategy
- Password: Roundtrip hash/verify, invalid password returns False, fast hasher params for tests
- WebAuthn: Build registration/authentication responses manually using fido2's
create()factory methods (AttestedCredentialData.create,AuthenticatorData.create,CollectedClientData.create, etc.) with real ES256 keys fromcryptographylibrary. No external test utility package needed. - MagicLink: In-memory SQLite fixtures, test create/validate/expired/used states
5. Dependencies
All already in pyproject.toml:
fido2>=2.1(python-fido2)argon2-cffi>=25.1
No new dependencies required.
File Structure
src/fastapi_oidc_op/
├── authn/
│ ├── __init__.py (exists, empty)
│ ├── password.py (new)
│ └── webauthn.py (new)
├── invite/
│ ├── __init__.py (exists, empty)
│ └── service.py (new)
tests/
├── test_authn/
│ ├── __init__.py (new)
│ ├── test_password.py (new)
│ └── test_webauthn.py (new)
├── test_invite/
│ ├── __init__.py (new)
│ └── test_service.py (new)