refactor: replace user authentication method with conditional authentication across multiple routers

This commit is contained in:
Daulet Amirkhanov 2025-08-20 18:51:31 +01:00
parent 560dd71228
commit ea633aedc1
13 changed files with 67 additions and 105 deletions

View file

@ -9,7 +9,7 @@ from fastapi import Form, File, UploadFile, Depends
from typing import List, Optional, Union, Literal
from cognee.modules.users.models import User
from cognee.modules.users.methods import get_optional_authenticated_user, get_default_user
from cognee.modules.users.methods import get_conditional_authenticated_user
from cognee.shared.utils import send_telemetry
from cognee.modules.pipelines.models import PipelineRunErrored
from cognee.shared.logging_utils import get_logger
@ -25,7 +25,7 @@ def get_add_router() -> APIRouter:
data: List[UploadFile] = File(default=None),
datasetName: Optional[str] = Form(default=None),
datasetId: Union[UUID, Literal[""], None] = Form(default=None, examples=[""]),
user: Optional[User] = Depends(get_optional_authenticated_user),
user: User = Depends(get_conditional_authenticated_user),
):
"""
Add data to a dataset for processing and knowledge graph construction.
@ -62,10 +62,6 @@ def get_add_router() -> APIRouter:
- The ALLOW_HTTP_REQUESTS environment variable controls URL processing
- datasetId value can only be the UUID of an already existing dataset
"""
# Use default user for anonymous requests
if user is None:
user = await get_default_user()
send_telemetry(
"Add API Endpoint Invoked",
user.id,

View file

@ -10,7 +10,7 @@ from starlette.status import WS_1000_NORMAL_CLOSURE, WS_1008_POLICY_VIOLATION
from cognee.api.DTO import InDTO
from cognee.modules.pipelines.methods import get_pipeline_run
from cognee.modules.users.models import User
from cognee.modules.users.methods import get_optional_authenticated_user, get_default_user
from cognee.modules.users.methods import get_conditional_authenticated_user
from cognee.modules.users.get_user_db import get_user_db_context
from cognee.modules.graph.methods import get_formatted_graph_data
from cognee.modules.users.get_user_manager import get_user_manager_context
@ -46,7 +46,7 @@ def get_cognify_router() -> APIRouter:
router = APIRouter()
@router.post("", response_model=dict)
async def cognify(payload: CognifyPayloadDTO, user: Optional[User] = Depends(get_optional_authenticated_user)):
async def cognify(payload: CognifyPayloadDTO, user: User = Depends(get_conditional_authenticated_user)):
"""
Transform datasets into structured knowledge graphs through cognitive processing.
@ -92,10 +92,6 @@ def get_cognify_router() -> APIRouter:
## Next Steps
After successful processing, use the search endpoints to query the generated knowledge graph for insights, relationships, and semantic search.
"""
# Use default user for anonymous requests
if user is None:
user = await get_default_user()
send_telemetry(
"Cognify API Endpoint Invoked",
user.id,

View file

@ -15,7 +15,7 @@ from cognee.modules.data.methods import create_dataset, get_datasets_by_name
from cognee.shared.logging_utils import get_logger
from cognee.api.v1.exceptions import DataNotFoundError, DatasetNotFoundError
from cognee.modules.users.models import User
from cognee.modules.users.methods import get_authenticated_user
from cognee.modules.users.methods import get_conditional_authenticated_user
from cognee.modules.users.permissions.methods import (
get_all_user_permission_datasets,
give_permission_on_dataset,
@ -74,7 +74,7 @@ def get_datasets_router() -> APIRouter:
router = APIRouter()
@router.get("", response_model=list[DatasetDTO])
async def get_datasets(user: User = Depends(get_authenticated_user)):
async def get_datasets(user: User = Depends(get_conditional_authenticated_user)):
"""
Get all datasets accessible to the authenticated user.
@ -114,7 +114,7 @@ def get_datasets_router() -> APIRouter:
@router.post("", response_model=DatasetDTO)
async def create_new_dataset(
dataset_data: DatasetCreationPayload, user: User = Depends(get_authenticated_user)
dataset_data: DatasetCreationPayload, user: User = Depends(get_conditional_authenticated_user)
):
"""
Create a new dataset or return existing dataset with the same name.
@ -175,7 +175,7 @@ def get_datasets_router() -> APIRouter:
@router.delete(
"/{dataset_id}", response_model=None, responses={404: {"model": ErrorResponseDTO}}
)
async def delete_dataset(dataset_id: UUID, user: User = Depends(get_authenticated_user)):
async def delete_dataset(dataset_id: UUID, user: User = Depends(get_conditional_authenticated_user)):
"""
Delete a dataset by its ID.
@ -216,7 +216,7 @@ def get_datasets_router() -> APIRouter:
responses={404: {"model": ErrorResponseDTO}},
)
async def delete_data(
dataset_id: UUID, data_id: UUID, user: User = Depends(get_authenticated_user)
dataset_id: UUID, data_id: UUID, user: User = Depends(get_conditional_authenticated_user)
):
"""
Delete a specific data item from a dataset.
@ -263,7 +263,7 @@ def get_datasets_router() -> APIRouter:
await delete_data(data)
@router.get("/{dataset_id}/graph", response_model=GraphDTO)
async def get_dataset_graph(dataset_id: UUID, user: User = Depends(get_authenticated_user)):
async def get_dataset_graph(dataset_id: UUID, user: User = Depends(get_conditional_authenticated_user)):
"""
Get the knowledge graph visualization for a dataset.
@ -293,7 +293,7 @@ def get_datasets_router() -> APIRouter:
response_model=list[DataDTO],
responses={404: {"model": ErrorResponseDTO}},
)
async def get_dataset_data(dataset_id: UUID, user: User = Depends(get_authenticated_user)):
async def get_dataset_data(dataset_id: UUID, user: User = Depends(get_conditional_authenticated_user)):
"""
Get all data items in a dataset.
@ -348,7 +348,7 @@ def get_datasets_router() -> APIRouter:
@router.get("/status", response_model=dict[str, PipelineRunStatus])
async def get_dataset_status(
datasets: Annotated[List[UUID], Query(alias="dataset")] = [],
user: User = Depends(get_authenticated_user),
user: User = Depends(get_conditional_authenticated_user),
):
"""
Get the processing status of datasets.
@ -395,7 +395,7 @@ def get_datasets_router() -> APIRouter:
@router.get("/{dataset_id}/data/{data_id}/raw", response_class=FileResponse)
async def get_raw_data(
dataset_id: UUID, data_id: UUID, user: User = Depends(get_authenticated_user)
dataset_id: UUID, data_id: UUID, user: User = Depends(get_conditional_authenticated_user)
):
"""
Download the raw data file for a specific data item.

View file

@ -4,7 +4,7 @@ from fastapi import APIRouter
from uuid import UUID
from cognee.shared.logging_utils import get_logger
from cognee.modules.users.models import User
from cognee.modules.users.methods import get_authenticated_user
from cognee.modules.users.methods import get_conditional_authenticated_user
from cognee.shared.utils import send_telemetry
logger = get_logger()
@ -18,7 +18,7 @@ def get_delete_router() -> APIRouter:
data_id: UUID,
dataset_id: UUID,
mode: str = "soft",
user: User = Depends(get_authenticated_user),
user: User = Depends(get_conditional_authenticated_user),
):
"""Delete data by its ID from the specified dataset.

View file

@ -5,7 +5,7 @@ from fastapi import APIRouter, Depends
from fastapi.responses import JSONResponse
from cognee.modules.users.models import User
from cognee.modules.users.methods import get_authenticated_user
from cognee.modules.users.methods import get_conditional_authenticated_user
from cognee.shared.utils import send_telemetry
@ -17,7 +17,7 @@ def get_permissions_router() -> APIRouter:
permission_name: str,
dataset_ids: List[UUID],
principal_id: UUID,
user: User = Depends(get_authenticated_user),
user: User = Depends(get_conditional_authenticated_user),
):
"""
Grant permission on datasets to a principal (user or role).
@ -65,7 +65,7 @@ def get_permissions_router() -> APIRouter:
)
@permissions_router.post("/roles")
async def create_role(role_name: str, user: User = Depends(get_authenticated_user)):
async def create_role(role_name: str, user: User = Depends(get_conditional_authenticated_user)):
"""
Create a new role.
@ -100,7 +100,7 @@ def get_permissions_router() -> APIRouter:
@permissions_router.post("/users/{user_id}/roles")
async def add_user_to_role(
user_id: UUID, role_id: UUID, user: User = Depends(get_authenticated_user)
user_id: UUID, role_id: UUID, user: User = Depends(get_conditional_authenticated_user)
):
"""
Add a user to a role.
@ -142,7 +142,7 @@ def get_permissions_router() -> APIRouter:
@permissions_router.post("/users/{user_id}/tenants")
async def add_user_to_tenant(
user_id: UUID, tenant_id: UUID, user: User = Depends(get_authenticated_user)
user_id: UUID, tenant_id: UUID, user: User = Depends(get_conditional_authenticated_user)
):
"""
Add a user to a tenant.
@ -183,7 +183,7 @@ def get_permissions_router() -> APIRouter:
return JSONResponse(status_code=200, content={"message": "User added to tenant"})
@permissions_router.post("/tenants")
async def create_tenant(tenant_name: str, user: User = Depends(get_authenticated_user)):
async def create_tenant(tenant_name: str, user: User = Depends(get_conditional_authenticated_user)):
"""
Create a new tenant.

View file

@ -21,7 +21,7 @@ from cognee.infrastructure.llm.config import (
get_llm_config,
)
from cognee.modules.users.models import User
from cognee.modules.users.methods import get_authenticated_user
from cognee.modules.users.methods import get_conditional_authenticated_user
def get_responses_router() -> APIRouter:
@ -73,7 +73,7 @@ def get_responses_router() -> APIRouter:
@router.post("/", response_model=ResponseBody)
async def create_response(
request: ResponseRequest,
user: User = Depends(get_authenticated_user),
user: User = Depends(get_conditional_authenticated_user),
) -> ResponseBody:
"""
OpenAI-compatible responses endpoint with function calling support.

View file

@ -9,7 +9,7 @@ from cognee.api.DTO import InDTO, OutDTO
from cognee.modules.users.exceptions.exceptions import PermissionDeniedError
from cognee.modules.users.models import User
from cognee.modules.search.operations import get_history
from cognee.modules.users.methods import get_optional_authenticated_user, get_default_user
from cognee.modules.users.methods import get_conditional_authenticated_user
from cognee.shared.utils import send_telemetry
@ -33,7 +33,7 @@ def get_search_router() -> APIRouter:
created_at: datetime
@router.get("", response_model=list[SearchHistoryItem])
async def get_search_history(user: Optional[User] = Depends(get_optional_authenticated_user)):
async def get_search_history(user: User = Depends(get_conditional_authenticated_user)):
"""
Get search history for the authenticated user.
@ -50,10 +50,6 @@ def get_search_router() -> APIRouter:
## Error Codes
- **500 Internal Server Error**: Error retrieving search history
"""
# Use default user for anonymous requests
if user is None:
user = await get_default_user()
send_telemetry(
"Search API Endpoint Invoked",
user.id,
@ -70,7 +66,7 @@ def get_search_router() -> APIRouter:
return JSONResponse(status_code=500, content={"error": str(error)})
@router.post("", response_model=list)
async def search(payload: SearchPayloadDTO, user: Optional[User] = Depends(get_optional_authenticated_user)):
async def search(payload: SearchPayloadDTO, user: User = Depends(get_conditional_authenticated_user)):
"""
Search for nodes in the graph database.
@ -97,10 +93,6 @@ def get_search_router() -> APIRouter:
- To search datasets not owned by the request sender, dataset UUID is needed
- If permission is denied, returns empty list instead of error
"""
# Use default user for anonymous requests
if user is None:
user = await get_default_user()
send_telemetry(
"Search API Endpoint Invoked",
user.id,

View file

@ -1,7 +1,7 @@
from fastapi import APIRouter
from cognee.api.DTO import InDTO, OutDTO
from typing import Union, Optional, Literal
from cognee.modules.users.methods import get_authenticated_user
from cognee.modules.users.methods import get_conditional_authenticated_user
from fastapi import Depends
from cognee.modules.users.models import User
from cognee.modules.settings.get_settings import LLMConfig, VectorDBConfig
@ -45,7 +45,7 @@ def get_settings_router() -> APIRouter:
router = APIRouter()
@router.get("", response_model=SettingsDTO)
async def get_settings(user: User = Depends(get_authenticated_user)):
async def get_settings(user: User = Depends(get_conditional_authenticated_user)):
"""
Get the current system settings.
@ -67,7 +67,7 @@ def get_settings_router() -> APIRouter:
@router.post("", response_model=None)
async def save_settings(
new_settings: SettingsPayloadDTO, user: User = Depends(get_authenticated_user)
new_settings: SettingsPayloadDTO, user: User = Depends(get_conditional_authenticated_user)
):
"""
Save or update system settings.

View file

@ -2,7 +2,7 @@ from fastapi import APIRouter, Depends
from fastapi.responses import HTMLResponse, JSONResponse
from uuid import UUID
from cognee.shared.logging_utils import get_logger
from cognee.modules.users.methods import get_authenticated_user
from cognee.modules.users.methods import get_conditional_authenticated_user
from cognee.modules.data.methods import get_authorized_existing_datasets
from cognee.modules.users.models import User
@ -16,7 +16,7 @@ def get_visualize_router() -> APIRouter:
router = APIRouter()
@router.get("", response_model=None)
async def visualize(dataset_id: UUID, user: User = Depends(get_authenticated_user)):
async def visualize(dataset_id: UUID, user: User = Depends(get_conditional_authenticated_user)):
"""
Generate an HTML visualization of the dataset's knowledge graph.

View file

@ -4,5 +4,4 @@ from .delete_user import delete_user
from .get_default_user import get_default_user
from .get_user_by_email import get_user_by_email
from .create_default_user import create_default_user
from .get_authenticated_user import get_authenticated_user
from .get_optional_authenticated_user import get_optional_authenticated_user
from .get_conditional_authenticated_user import get_conditional_authenticated_user, REQUIRE_AUTHENTICATION

View file

@ -1,48 +0,0 @@
from ..get_fastapi_users import get_fastapi_users
fastapi_users = get_fastapi_users()
get_authenticated_user = fastapi_users.current_user(active=True)
# from types import SimpleNamespace
# from ..get_fastapi_users import get_fastapi_users
# from fastapi import HTTPException, Security
# from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
# import os
# import jwt
# from uuid import UUID
# fastapi_users = get_fastapi_users()
# # Allows Swagger to understand authorization type and allow single sign on for the Swagger docs to test backend
# bearer_scheme = HTTPBearer(scheme_name="BearerAuth", description="Paste **Bearer <JWT>**")
# async def get_authenticated_user(
# creds: HTTPAuthorizationCredentials = Security(bearer_scheme),
# ) -> SimpleNamespace:
# """
# Extract and validate the JWT presented in the Authorization header.
# """
# if creds is None: # header missing
# raise HTTPException(status_code=401, detail="Not authenticated")
# if creds.scheme.lower() != "bearer": # shouldn't happen extra guard
# raise HTTPException(status_code=401, detail="Invalid authentication scheme")
# token = creds.credentials
# try:
# payload = jwt.decode(
# token, os.getenv("FASTAPI_USERS_JWT_SECRET", "super_secret"), algorithms=["HS256"]
# )
# auth_data = SimpleNamespace(id=UUID(payload["user_id"]))
# return auth_data
# except jwt.ExpiredSignatureError:
# raise HTTPException(status_code=401, detail="Token has expired")
# except jwt.InvalidTokenError:
# raise HTTPException(status_code=401, detail="Invalid token")

View file

@ -0,0 +1,35 @@
import os
from typing import Optional
from fastapi import Depends
from ..models import User
from ..get_fastapi_users import get_fastapi_users
from .get_default_user import get_default_user
# Check environment variable to determine authentication requirement
REQUIRE_AUTHENTICATION = os.getenv("REQUIRE_AUTHENTICATION", "false").lower() == "true"
fastapi_users = get_fastapi_users()
if REQUIRE_AUTHENTICATION:
# When REQUIRE_AUTHENTICATION=true, enforce authentication (original behavior)
_auth_dependency = fastapi_users.current_user(active=True)
else:
# When REQUIRE_AUTHENTICATION=false (default), make authentication optional
_auth_dependency = fastapi_users.current_user(
optional=True, # Returns None instead of raising HTTPException(401)
active=True # Still require users to be active when authenticated
)
async def get_conditional_authenticated_user(user: Optional[User] = Depends(_auth_dependency)) -> User:
"""
Get authenticated user with environment-controlled behavior:
- If REQUIRE_AUTHENTICATION=true: Enforces authentication (raises 401 if not authenticated)
- If REQUIRE_AUTHENTICATION=false: Falls back to default user if not authenticated
Always returns a User object for consistent typing.
"""
if user is None and not REQUIRE_AUTHENTICATION:
# When authentication is optional and user is None, use default user
user = await get_default_user()
return user

View file

@ -1,8 +0,0 @@
from ..get_fastapi_users import get_fastapi_users
# Create optional authenticated user dependency using FastAPI Users' built-in optional parameter
fastapi_users = get_fastapi_users()
get_optional_authenticated_user = fastapi_users.current_user(
optional=True, # Returns None instead of raising HTTPException(401)
active=True # Still require users to be active when authenticated
)