miningniti-api / app /api /deps.py
Milan Soni
Deploy MiningNiti API with production RAG pipeline
3a7eb07
Raw
History Blame Contribute Delete
3.24 kB
"""
API Dependencies
Shared dependencies for FastAPI endpoints
"""
import hashlib
import logging
from typing import Optional
from fastapi import Depends, Header, Request
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from sqlalchemy.orm import Session
from app.core.exceptions import AuthenticationError
from app.core.security import extract_user_email, extract_user_id, verify_jwt_token
from app.db.session import SessionLocal, get_db
from app.models.audit import AuditAction, create_audit_log
from app.models.user import User
logger = logging.getLogger(__name__)
def _anonymize_user_id(user_id: str) -> str:
"""Create a truncated hash of user_id for safe logging."""
return hashlib.sha256(user_id.encode()).hexdigest()[:12]
# Security scheme
security = HTTPBearer()
async def get_current_user_id(
credentials: HTTPAuthorizationCredentials = Depends(security),
) -> str:
"""
Dependency to extract and verify user ID from JWT.
Returns Clerk user ID string.
"""
token = credentials.credentials
payload = await verify_jwt_token(token)
return extract_user_id(payload)
async def get_current_user(
user_id: str = Depends(get_current_user_id), db: Session = Depends(get_db)
) -> User:
"""
Dependency to get current user model from database.
Creates user record if it doesn't exist (first login).
"""
user = db.query(User).filter(User.clerk_user_id == user_id).first()
if not user:
# Auto-create user on first access
user = User(clerk_user_id=user_id, is_active=True)
db.add(user)
db.commit()
db.refresh(user)
logger.info(f"Created new user: {_anonymize_user_id(user_id)}")
return user
async def get_optional_user(
credentials: Optional[HTTPAuthorizationCredentials] = Depends(
HTTPBearer(auto_error=False)
),
db: Session = Depends(get_db),
) -> Optional[User]:
"""
Dependency for endpoints that work with or without auth.
Returns User if authenticated, None otherwise.
"""
if not credentials:
return None
try:
token = credentials.credentials
payload = await verify_jwt_token(token)
user_id = extract_user_id(payload)
return db.query(User).filter(User.clerk_user_id == user_id).first()
except Exception:
return None
def get_client_ip(request: Request) -> str:
"""Extract client IP address from request"""
forwarded = request.headers.get("X-Forwarded-For")
if forwarded:
return forwarded.split(",")[0].strip()
return request.client.host if request.client else "unknown"
def get_user_agent(request: Request) -> str:
"""Extract user agent from request"""
return request.headers.get("User-Agent", "unknown")
async def audit_middleware(
request: Request, user_id: str = Depends(get_current_user_id)
):
"""
Middleware-like dependency to log API access.
Add to endpoints that need audit logging.
"""
# This is called after auth, so we have user_id
# Actual logging happens in endpoint handlers
return {
"user_id": user_id,
"ip_address": get_client_ip(request),
"user_agent": get_user_agent(request),
}