Architecture¶
Component Graph¶
graph TD
A[AuthController] --> S[AuthService]
A --> J[JWTProvider]
O[OIDCController] --> J
G[GroupController] --> GS[GroupService]
S --> UR[UserRepository]
S --> TR[RefreshTokenRepository]
S --> GR[GroupRepository]
S --> P[PasswordService]
S --> J
S --> C[AuthSettings]
GS --> GR
J --> C
UR --> SM[SessionManager]
TR --> SM
GR --> SM Layer Separation¶
| Layer | Components | Responsibility |
|---|---|---|
| Config | AuthSettings | Load settings from YAML/env |
| Models | User, RefreshToken, Group, GroupMember | SQLAlchemy entity definitions |
| Repository | UserRepository, RefreshTokenRepository, GroupRepository | Database access (CRUD) |
| Service | AuthService, GroupService | Business logic, validation |
| Security | JWTProvider, PasswordService | Token creation, password hashing |
| Routes | AuthController, GroupController, OIDCController | HTTP endpoints |
| Bootstrap | main.py | Container creation, server startup |
Dependency Injection¶
All components are wired via pico-ioc decorators:
@component- Auto-registered service/repository@configured(prefix="auth", mapping="tree")- Config from YAML@controller(prefix="/api/v1/auth")- FastAPI route class
The container is bootstrapped in main.py:
Database¶
- ORM: SQLAlchemy 2.0 async (via pico-sqlalchemy)
- Default engine: SQLite + aiosqlite
- Tables:
users,refresh_tokens,groups,group_members - Schema creation:
create_tables(session_manager)on startup
Key Storage¶
Keys are stored in ~/.pico-auth/ and auto-generated on first run.
RSA (RS256):
private.pem(mode 0600) — Used for JWT signingpublic.pem— Used for JWT verification and JWKS endpoint
ML-DSA (ML-DSA-65, ML-DSA-87):
pqc_secret.bin(mode 0600) — Used for JWT signingpqc_public.bin— Used for JWT verification and JWKS endpoint
The algorithm is selected via auth.algorithm in configuration. JWKS serves RSA keys (kty: "RSA") or ML-DSA keys (kty: "AKP") accordingly.