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 typing import List, Optional, Union, Literal
from cognee.modules.users.models import User 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.shared.utils import send_telemetry
from cognee.modules.pipelines.models import PipelineRunErrored from cognee.modules.pipelines.models import PipelineRunErrored
from cognee.shared.logging_utils import get_logger from cognee.shared.logging_utils import get_logger
@ -25,7 +25,7 @@ def get_add_router() -> APIRouter:
data: List[UploadFile] = File(default=None), data: List[UploadFile] = File(default=None),
datasetName: Optional[str] = Form(default=None), datasetName: Optional[str] = Form(default=None),
datasetId: Union[UUID, Literal[""], None] = Form(default=None, examples=[""]), 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. 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 - The ALLOW_HTTP_REQUESTS environment variable controls URL processing
- datasetId value can only be the UUID of an already existing dataset - 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( send_telemetry(
"Add API Endpoint Invoked", "Add API Endpoint Invoked",
user.id, 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.api.DTO import InDTO
from cognee.modules.pipelines.methods import get_pipeline_run from cognee.modules.pipelines.methods import get_pipeline_run
from cognee.modules.users.models import User 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.users.get_user_db import get_user_db_context
from cognee.modules.graph.methods import get_formatted_graph_data from cognee.modules.graph.methods import get_formatted_graph_data
from cognee.modules.users.get_user_manager import get_user_manager_context from cognee.modules.users.get_user_manager import get_user_manager_context
@ -46,7 +46,7 @@ def get_cognify_router() -> APIRouter:
router = APIRouter() router = APIRouter()
@router.post("", response_model=dict) @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. Transform datasets into structured knowledge graphs through cognitive processing.
@ -92,10 +92,6 @@ def get_cognify_router() -> APIRouter:
## Next Steps ## Next Steps
After successful processing, use the search endpoints to query the generated knowledge graph for insights, relationships, and semantic search. 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( send_telemetry(
"Cognify API Endpoint Invoked", "Cognify API Endpoint Invoked",
user.id, 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.shared.logging_utils import get_logger
from cognee.api.v1.exceptions import DataNotFoundError, DatasetNotFoundError from cognee.api.v1.exceptions import DataNotFoundError, DatasetNotFoundError
from cognee.modules.users.models import User 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 ( from cognee.modules.users.permissions.methods import (
get_all_user_permission_datasets, get_all_user_permission_datasets,
give_permission_on_dataset, give_permission_on_dataset,
@ -74,7 +74,7 @@ def get_datasets_router() -> APIRouter:
router = APIRouter() router = APIRouter()
@router.get("", response_model=list[DatasetDTO]) @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. Get all datasets accessible to the authenticated user.
@ -114,7 +114,7 @@ def get_datasets_router() -> APIRouter:
@router.post("", response_model=DatasetDTO) @router.post("", response_model=DatasetDTO)
async def create_new_dataset( 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. Create a new dataset or return existing dataset with the same name.
@ -175,7 +175,7 @@ def get_datasets_router() -> APIRouter:
@router.delete( @router.delete(
"/{dataset_id}", response_model=None, responses={404: {"model": ErrorResponseDTO}} "/{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. Delete a dataset by its ID.
@ -216,7 +216,7 @@ def get_datasets_router() -> APIRouter:
responses={404: {"model": ErrorResponseDTO}}, responses={404: {"model": ErrorResponseDTO}},
) )
async def delete_data( 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. Delete a specific data item from a dataset.
@ -263,7 +263,7 @@ def get_datasets_router() -> APIRouter:
await delete_data(data) await delete_data(data)
@router.get("/{dataset_id}/graph", response_model=GraphDTO) @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. Get the knowledge graph visualization for a dataset.
@ -293,7 +293,7 @@ def get_datasets_router() -> APIRouter:
response_model=list[DataDTO], response_model=list[DataDTO],
responses={404: {"model": ErrorResponseDTO}}, 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. Get all data items in a dataset.
@ -348,7 +348,7 @@ def get_datasets_router() -> APIRouter:
@router.get("/status", response_model=dict[str, PipelineRunStatus]) @router.get("/status", response_model=dict[str, PipelineRunStatus])
async def get_dataset_status( async def get_dataset_status(
datasets: Annotated[List[UUID], Query(alias="dataset")] = [], 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. 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) @router.get("/{dataset_id}/data/{data_id}/raw", response_class=FileResponse)
async def get_raw_data( 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. 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 uuid import UUID
from cognee.shared.logging_utils import get_logger from cognee.shared.logging_utils import get_logger
from cognee.modules.users.models import User 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 from cognee.shared.utils import send_telemetry
logger = get_logger() logger = get_logger()
@ -18,7 +18,7 @@ def get_delete_router() -> APIRouter:
data_id: UUID, data_id: UUID,
dataset_id: UUID, dataset_id: UUID,
mode: str = "soft", 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. """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 fastapi.responses import JSONResponse
from cognee.modules.users.models import User 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 from cognee.shared.utils import send_telemetry
@ -17,7 +17,7 @@ def get_permissions_router() -> APIRouter:
permission_name: str, permission_name: str,
dataset_ids: List[UUID], dataset_ids: List[UUID],
principal_id: 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). Grant permission on datasets to a principal (user or role).
@ -65,7 +65,7 @@ def get_permissions_router() -> APIRouter:
) )
@permissions_router.post("/roles") @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. Create a new role.
@ -100,7 +100,7 @@ def get_permissions_router() -> APIRouter:
@permissions_router.post("/users/{user_id}/roles") @permissions_router.post("/users/{user_id}/roles")
async def add_user_to_role( 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. Add a user to a role.
@ -142,7 +142,7 @@ def get_permissions_router() -> APIRouter:
@permissions_router.post("/users/{user_id}/tenants") @permissions_router.post("/users/{user_id}/tenants")
async def add_user_to_tenant( 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. 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"}) return JSONResponse(status_code=200, content={"message": "User added to tenant"})
@permissions_router.post("/tenants") @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. Create a new tenant.

View file

@ -21,7 +21,7 @@ from cognee.infrastructure.llm.config import (
get_llm_config, get_llm_config,
) )
from cognee.modules.users.models import User 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: def get_responses_router() -> APIRouter:
@ -73,7 +73,7 @@ def get_responses_router() -> APIRouter:
@router.post("/", response_model=ResponseBody) @router.post("/", response_model=ResponseBody)
async def create_response( async def create_response(
request: ResponseRequest, request: ResponseRequest,
user: User = Depends(get_authenticated_user), user: User = Depends(get_conditional_authenticated_user),
) -> ResponseBody: ) -> ResponseBody:
""" """
OpenAI-compatible responses endpoint with function calling support. 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.exceptions.exceptions import PermissionDeniedError
from cognee.modules.users.models import User from cognee.modules.users.models import User
from cognee.modules.search.operations import get_history 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 from cognee.shared.utils import send_telemetry
@ -33,7 +33,7 @@ def get_search_router() -> APIRouter:
created_at: datetime created_at: datetime
@router.get("", response_model=list[SearchHistoryItem]) @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. Get search history for the authenticated user.
@ -50,10 +50,6 @@ def get_search_router() -> APIRouter:
## Error Codes ## Error Codes
- **500 Internal Server Error**: Error retrieving search history - **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( send_telemetry(
"Search API Endpoint Invoked", "Search API Endpoint Invoked",
user.id, user.id,
@ -70,7 +66,7 @@ def get_search_router() -> APIRouter:
return JSONResponse(status_code=500, content={"error": str(error)}) return JSONResponse(status_code=500, content={"error": str(error)})
@router.post("", response_model=list) @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. 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 - To search datasets not owned by the request sender, dataset UUID is needed
- If permission is denied, returns empty list instead of error - 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( send_telemetry(
"Search API Endpoint Invoked", "Search API Endpoint Invoked",
user.id, user.id,

View file

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

View file

@ -2,7 +2,7 @@ from fastapi import APIRouter, Depends
from fastapi.responses import HTMLResponse, JSONResponse from fastapi.responses import HTMLResponse, JSONResponse
from uuid import UUID from uuid import UUID
from cognee.shared.logging_utils import get_logger 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.data.methods import get_authorized_existing_datasets
from cognee.modules.users.models import User from cognee.modules.users.models import User
@ -16,7 +16,7 @@ def get_visualize_router() -> APIRouter:
router = APIRouter() router = APIRouter()
@router.get("", response_model=None) @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. 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_default_user import get_default_user
from .get_user_by_email import get_user_by_email from .get_user_by_email import get_user_by_email
from .create_default_user import create_default_user from .create_default_user import create_default_user
from .get_authenticated_user import get_authenticated_user from .get_conditional_authenticated_user import get_conditional_authenticated_user, REQUIRE_AUTHENTICATION
from .get_optional_authenticated_user import get_optional_authenticated_user

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
)