rename package directory fastapi_oidc_op → porchlight
This commit is contained in:
parent
32b75cf92d
commit
c5a80b51de
49 changed files with 7332 additions and 0 deletions
78
docs/plans/2026-02-13-auth-services-design.md
Normal file
78
docs/plans/2026-02-13-auth-services-design.md
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
# 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:
|
||||
1. **PasswordService** — Argon2 hash/verify
|
||||
2. **WebAuthnService** — FIDO2 registration/authentication via python-fido2
|
||||
3. **MagicLinkService** — Invite token create/validate
|
||||
|
||||
## Design Decisions
|
||||
|
||||
### 1. PasswordService (stateless, pure crypto)
|
||||
|
||||
- Wraps `argon2-cffi` `PasswordHasher`
|
||||
- Two methods: `hash(password) -> str`, `verify(hash, password) -> bool`
|
||||
- `PasswordHasher` injected via constructor for testability
|
||||
- No repository dependency — caller reads/writes credentials
|
||||
- Uses argon2-cffi OWASP-recommended defaults
|
||||
- `verify()` returns `bool` (catches `VerifyMismatchError` internally)
|
||||
|
||||
### 2. WebAuthnService (class wrapping Fido2Server)
|
||||
|
||||
- Constructor takes `rp_id`, `rp_name`, `origin` — creates `Fido2Server` internally
|
||||
- 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 via `secrets.token_urlsafe(32)`
|
||||
- `validate(token) -> MagicLink | None` — checks exists, not used, not expired
|
||||
- `mark_used(token) -> bool` — delegates to repo
|
||||
- `cleanup_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 from `cryptography` library. 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)
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue