fix: make FrontendType mandatory in require_module_access

The require_module_access dependency was using path-based detection to
determine admin vs vendor authentication, which failed for API routes
(/api/v1/admin/*) because it only checked for /admin/*.

Changes:
- Make frontend_type parameter mandatory (was optional with fallback)
- Remove path-based detection logic from require_module_access
- Update all 33 module route files to pass explicit FrontendType:
  - 15 admin routes use FrontendType.ADMIN
  - 18 vendor routes use FrontendType.VENDOR

This ensures authentication method is explicitly declared at route
definition time, making it independent of URL structure and future-proof
for API version changes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-02 22:09:21 +01:00
parent 01e7602dcb
commit 9a0dd84035
34 changed files with 83 additions and 45 deletions

View File

@@ -54,6 +54,7 @@ from middleware.rate_limiter import RateLimiter
from app.modules.tenancy.models import User as UserModel
from app.modules.tenancy.models import Vendor
from models.schema.auth import UserContext
from app.modules.enums import FrontendType
# Initialize dependencies
security = HTTPBearer(auto_error=False) # auto_error=False prevents automatic 403
@@ -429,7 +430,7 @@ def get_admin_with_platform_context(
# ============================================================================
def require_module_access(module_code: str):
def require_module_access(module_code: str, frontend_type: FrontendType):
"""
Dependency factory for module-based route access control.
@@ -438,14 +439,18 @@ def require_module_access(module_code: str):
tied to a specific menu item.
Usage:
@router.get("/admin/billing/stripe-config")
async def stripe_config(
current_user: User = Depends(require_module_access("billing")),
):
...
admin_router = APIRouter(
dependencies=[Depends(require_module_access("messaging", FrontendType.ADMIN))]
)
vendor_router = APIRouter(
dependencies=[Depends(require_module_access("billing", FrontendType.VENDOR))]
)
Args:
module_code: Module code to check (e.g., "billing", "marketplace")
frontend_type: Frontend type (ADMIN or VENDOR). Required to determine
which authentication method to use.
Returns:
Dependency function that validates module access and returns User
@@ -459,12 +464,13 @@ def require_module_access(module_code: str):
vendor_token: str | None = Cookie(None),
db: Session = Depends(get_db),
) -> UserContext:
# Try admin auth first, then vendor
user_context = None
platform_id = None
# Check if this is an admin request
if admin_token or (credentials and request.url.path.startswith("/admin")):
# Use explicit frontend_type to determine authentication method
is_admin_request = frontend_type == FrontendType.ADMIN
if is_admin_request:
try:
user_context = get_current_admin_from_cookie_or_header(
request, credentials, admin_token, db
@@ -477,12 +483,11 @@ def require_module_access(module_code: str):
platform = getattr(request.state, "admin_platform", None)
if platform:
platform_id = platform.id
# Note: token_platform_id is not on UserContext, would need to be added
except Exception:
pass
# Check if this is a vendor request
if not user_context and (vendor_token or (credentials and "/vendor/" in request.url.path)):
# Handle vendor request
if not user_context and frontend_type == FrontendType.VENDOR:
try:
user_context = get_current_vendor_from_cookie_or_header(
request, credentials, vendor_token, db