Use Case
The src/auth/ module currently conflates two distinct concerns: authentication (identity verification) and authorization (permission checking). This violates Domain-Driven Design principles and creates ambiguous imports.
Current problems:
- Unclear imports:
from src.auth import require_permissions - is this authn or authz?
- Namespace ambiguity: "auth" traditionally means authentication, but module contains both
- Mixed responsibilities:
src/auth/__init__.py exports both identity (User, AuthenticationService) and access control (Permission, Role, PermissionService)
- DDD violation: Authentication and Authorization are separate bounded contexts
Examples of confusion:
from src.auth import (
current_user, # Authentication
require_permissions, # Authorization
AuthenticationService, # Authentication
Permission, Role # Authorization
)
Proposed Solution
Separate into two top-level modules following DDD bounded contexts:
src/
├── auth/ # Authentication (identity verification)
│ ├── service.py # AuthenticationService (login/refresh/logout)
│ ├── manager.py # UserManager (fastapi-users integration)
│ ├── backend.py # JWT strategy + RefreshTokenManager
│ ├── models.py # User, OAuthAccount
│ ├── schemas.py # TokenResponse, UserRead, UserCreate, UserUpdate
│ ├── exceptions.py # Authentication exceptions
│ └── __init__.py # Export: current_user, AuthenticationService, User, etc.
│
└── rbac/ # Authorization (access control)
├── service.py # PermissionService (permission matching logic)
├── repository.py # PermissionRepository (database queries)
├── dependencies.py # require_permissions, require_roles, owner_or_perm
├── models.py # Permission, Role, UserRole, RolePermission
├── exceptions.py # InsufficientPermissionException, InsufficientRoleException
└── __init__.py # Export: require_permissions, require_roles, Permission, etc.
Import clarity after refactor:
from src.auth import current_user, AuthenticationService
from src.rbac import require_permissions, require_roles, owner_or_perm
Migration steps:
- Create
src/rbac/ directory
- Move
src/auth/rbac.py → src/rbac/service.py + src/rbac/repository.py + src/rbac/dependencies.py
- Extract RBAC models from
src/auth/models.py → src/rbac/models.py
- Extract RBAC exceptions from
src/auth/exceptions.py → src/rbac/exceptions.py
- Update all imports across codebase
- Update tests (
tests/auth/test_rbac.py → tests/rbac/)
- Update documentation and
.claude/skills/backend-patterns/SKILL.md
Alternatives Considered
Alternative A: Submodules under src/auth/
src/auth/
├── authn/
└── authz/
- Pros: Keeps related concepts together
- Cons: Still ambiguous ("auth" module name unclear), deeper nesting
Alternative B: Rename to be explicit
src/authentication/
src/authorization/
- Pros: Very clear naming
- Cons: Verbose, breaks from existing "auth" convention
Why proposed solution is better:
- "RBAC" already established (branch
feat/auth-rbac, file rbac.py)
- Top-level separation clearer than submodules
- "auth" for authentication is industry standard
- "rbac" is self-documenting for authorization
Implementation Notes
Affected files (update imports):
src/http/routers/auth.py - uses AuthenticationService
src/http/routers/oauth.py - uses current_user
src/audit/dependencies.py - may use auth models
- All test files in
tests/integration/test_auth*.py and tests/integration/test_rbac.py
.claude/skills/backend-patterns/SKILL.md - documentation references
Dependency considerations:
src/rbac/dependencies.py depends on src.auth.current_user (authentication) - this is correct cross-module dependency
src/audit/service.py audits both authentication and authorization events - should import from both modules
Breaking changes:
- All imports from
src.auth containing RBAC entities must update
- External code importing
from src.auth import Permission, Role will break
Migration strategy:
- Phase 1: Create
src/rbac/ with all RBAC code
- Phase 2: Add deprecation warnings in
src/auth/__init__.py for RBAC exports
- Phase 3: Update all internal imports
- Phase 4: Remove deprecated exports from
src/auth/__init__.py
Testing strategy:
- All existing tests must pass after refactor
- Verify no circular import issues
- Run full integration test suite
Follow DDD bounded contexts:
- Authentication context: User identity, sessions, tokens
- Authorization context: Permissions, roles, access control
- Clear boundaries enable independent evolution
Use Case
The
src/auth/module currently conflates two distinct concerns: authentication (identity verification) and authorization (permission checking). This violates Domain-Driven Design principles and creates ambiguous imports.Current problems:
from src.auth import require_permissions- is this authn or authz?src/auth/__init__.pyexports both identity (User, AuthenticationService) and access control (Permission, Role, PermissionService)Examples of confusion:
Proposed Solution
Separate into two top-level modules following DDD bounded contexts:
Import clarity after refactor:
Migration steps:
src/rbac/directorysrc/auth/rbac.py→src/rbac/service.py+src/rbac/repository.py+src/rbac/dependencies.pysrc/auth/models.py→src/rbac/models.pysrc/auth/exceptions.py→src/rbac/exceptions.pytests/auth/test_rbac.py→tests/rbac/).claude/skills/backend-patterns/SKILL.mdAlternatives Considered
Alternative A: Submodules under
src/auth/Alternative B: Rename to be explicit
Why proposed solution is better:
feat/auth-rbac, filerbac.py)Implementation Notes
Affected files (update imports):
src/http/routers/auth.py- usesAuthenticationServicesrc/http/routers/oauth.py- usescurrent_usersrc/audit/dependencies.py- may use auth modelstests/integration/test_auth*.pyandtests/integration/test_rbac.py.claude/skills/backend-patterns/SKILL.md- documentation referencesDependency considerations:
src/rbac/dependencies.pydepends onsrc.auth.current_user(authentication) - this is correct cross-module dependencysrc/audit/service.pyaudits both authentication and authorization events - should import from both modulesBreaking changes:
src.authcontaining RBAC entities must updatefrom src.auth import Permission, Rolewill breakMigration strategy:
src/rbac/with all RBAC codesrc/auth/__init__.pyfor RBAC exportssrc/auth/__init__.pyTesting strategy:
Follow DDD bounded contexts: