Date: 2025-11-04
Branch: feature/api-auth-middleware-coverage
Purpose: Establish comprehensive authentication testing for all API endpoints
We have a mature OAuth 2.0 + RBAC authentication system (ADR-054, ADR-028):
Authentication Methods:
- OAuth 2.0 access tokens (primary)
- API keys (secondary, starts with
kg_sk_) - Client credentials flow
- Device code flow
- Personal client flow
Authorization:
- Dynamic RBAC with permission checking
- Role-based access control (
require_role()) - Fine-grained permissions (
require_permission()) - Scope support (global, instance, filter-scoped)
Key Files:
api/app/dependencies/auth.py- FastAPI dependency injection for authapi/app/lib/auth.py- Core auth logicapi/app/middleware/auth.py- Legacy placeholder (Phase 1)api/app/models/auth.py- Auth data modelsapi/app/routes/auth.py- Auth endpointsapi/app/routes/oauth.py- OAuth endpointsapi/app/routes/rbac.py- RBAC management
Pattern:
import pytest
from fastapi.testclient import TestClient
@pytest.fixture
def authenticated_client(app):
"""Create test client with valid auth token"""
client = TestClient(app)
# Create test user and get token
user = create_test_user("testuser", "admin")
token = create_access_token_for_user(user.id)
# Inject token into client headers
client.headers = {
"Authorization": f"Bearer {token}"
}
return client
@pytest.fixture
def anonymous_client(app):
"""Create test client without authentication"""
return TestClient(app)Benefits:
- Reusable across tests
- Clear separation of authenticated vs anonymous
- Can scope fixtures (function, class, module, session)
Pattern:
from fastapi import Depends
from api.app.dependencies.auth import get_current_user
@pytest.fixture
def override_auth(app):
"""Override auth dependency to bypass real authentication"""
def mock_current_user():
return UserInDB(
id=1,
username="testuser",
role="admin",
disabled=False
)
app.dependency_overrides[get_current_user] = mock_current_user
yield
app.dependency_overrides.clear()Benefits:
- Faster tests (skip real auth flow)
- Test business logic independently
- Easy to test different user roles/permissions
Why: FastAPI recommends router-level dependencies for authentication:
- Better code readability
- Easier to test individual routes
- More maintainable than conditional middleware
Implementation:
# ✅ Good: Router-level dependency
router = APIRouter(dependencies=[Depends(get_current_user)])
# ❌ Avoid: Global middleware for auth
# (middleware is better for logging, CORS, etc.)Approach: OpenAPI Schema Introspection
FastAPI generates an OpenAPI schema accessible via app.openapi(). We can:
- Parse all endpoints from schema
- Categorize by auth requirements
- Verify protected endpoints actually require auth
- Ensure test coverage for all endpoints
Pattern:
def test_all_protected_endpoints_require_auth(app, anonymous_client):
"""Verify all protected endpoints reject unauthenticated requests"""
# Get all routes from OpenAPI schema
openapi_schema = app.openapi()
for path, methods in openapi_schema["paths"].items():
for method, details in methods.items():
# Check if endpoint requires auth (has security scheme)
if "security" in details:
response = anonymous_client.request(method.upper(), path)
assert response.status_code in [401, 403], \
f"{method.upper()} {path} should require auth"Installation:
pip install pytest-covUsage:
# Run tests with coverage report
pytest --cov=api/app --cov-report=html
# Focus on specific modules
pytest tests/test_auth.py --cov=api/app/dependencies/auth --cov-report=term-missingUnit Tests:
- Use
dependency_overridesto mock auth - Test business logic in isolation
- Fast, no database required
Integration Tests:
- Use real auth flow (create user, get token)
- Test end-to-end authentication
- Slower, requires database
Best Practice: Use both! Unit tests for coverage, integration tests for confidence.
-
Inventory all API endpoints
- List all route files
- Extract all endpoints with method + path
- Document current auth requirements
-
Categorize endpoints by auth needs
- Public (no auth): health checks, public queries
- Authenticated: most CRUD operations
- Admin-only: database reset, user management
- Permission-based: resource-specific actions
-
Identify gaps
- Which endpoints should have auth but don't?
- Which endpoints have auth but shouldn't?
- Are auth requirements documented?
-
Create test fixtures
authenticated_client(admin role)user_client(regular user role)anonymous_client(no auth)
-
Write systematic tests
- Test all public endpoints work without auth
- Test all protected endpoints require auth
- Test role-based restrictions
- Test permission-based restrictions
-
Add OpenAPI schema validation
- Verify schema correctly marks protected endpoints
- Ensure security schemes are documented
- Test that schema matches implementation
-
CI/CD Integration
- Add auth tests to test suite
- Require passing auth tests for merges
- Generate coverage reports
-
Documentation
- Document auth requirements per endpoint
- Add testing guide for developers
- Create ADR for auth testing strategy
-
Continuous Improvement
- Monitor for new endpoints without tests
- Update tests when auth requirements change
- Periodic security audits
Python Packages:
pytest- Test frameworkpytest-cov- Coverage measurementpytest-asyncio- Async test supportfastapi.testclient.TestClient- Built-in test client
Useful Patterns:
- Fixtures for reusable test clients
- Dependency overrides for mocking
- Parametrized tests for multiple scenarios
- Schema introspection for validation
References:
- FastAPI Testing Docs: https://fastapi.tiangolo.com/tutorial/testing/
- pytest-cov: https://pytest-cov.readthedocs.io/
- ADR-054: OAuth 2.0 Authentication
- ADR-028: Dynamic RBAC
- Create endpoint inventory script
- Audit current auth coverage
- Design test fixtures and utilities
- Write comprehensive auth test suite
- Document findings in ADR
- Integrate into CI/CD pipeline
Status: Research complete, ready for implementation Owner: Engineering Team Priority: High (security-critical)