""" API Keys API Endpoints This module provides REST API endpoints for managing API keys: - POST /api/api-keys - Create a new API key - GET /api/api-keys - List all API keys for the authenticated user - DELETE /api/api-keys/{key_id} - Revoke/delete an API key """ from fastapi import APIRouter, Depends, HTTPException from typing import List from uuid import UUID from services.api_keys import ( APIKeyService, APIKeyCreateRequest, APIKeyResponse, APIKeyCreateResponse, ) from services.supabase import DBConnection from utils.auth_utils import get_current_user_id_from_jwt from utils.logger import logger router = APIRouter() async def get_api_key_service() -> APIKeyService: """Dependency to get API key service instance""" db = DBConnection() await db.initialize() return APIKeyService(db) async def get_account_id_from_user_id(user_id: str) -> UUID: """Get account ID from user ID using basejump accounts table""" try: db = DBConnection() await db.initialize() client = await db.client # Query the basejump.accounts table for the user's primary account result = ( await client.schema("basejump") .table("accounts") .select("id") .eq("primary_owner_user_id", user_id) .eq("personal_account", True) # Get the user's personal account .limit(1) .execute() ) if not result.data: raise HTTPException(status_code=404, detail="User account not found") return UUID(result.data[0]["id"]) except Exception as e: logger.error(f"Error getting account ID: {e}") raise HTTPException(status_code=500, detail="Failed to get user account") @router.post("/api-keys", response_model=APIKeyCreateResponse) async def create_api_key( request: APIKeyCreateRequest, user_id: str = Depends(get_current_user_id_from_jwt), api_key_service: APIKeyService = Depends(get_api_key_service), ): """ Create a new API key for the authenticated user Args: request: API key creation request with title, description, and expiration user_id: Authenticated user ID from JWT or API key api_key_service: API key service instance Returns: APIKeyCreateResponse: The newly created API key details including the key value """ try: account_id = await get_account_id_from_user_id(user_id) logger.info( "Creating API key", user_id=user_id, account_id=str(account_id), title=request.title, ) api_key = await api_key_service.create_api_key(account_id, request) logger.info( "API key created successfully", user_id=user_id, key_id=str(api_key.key_id), title=api_key.title, ) return api_key except HTTPException: raise except Exception as e: logger.error(f"Unexpected error creating API key: {e}", exc_info=True) raise HTTPException(status_code=500, detail="Failed to create API key") @router.get("/api-keys", response_model=List[APIKeyResponse]) async def list_api_keys( user_id: str = Depends(get_current_user_id_from_jwt), api_key_service: APIKeyService = Depends(get_api_key_service), ): """ List all API keys for the authenticated user Args: user_id: Authenticated user ID from JWT or API key api_key_service: API key service instance Returns: List[APIKeyResponse]: List of API keys (without the actual key values) """ try: account_id = await get_account_id_from_user_id(user_id) logger.debug("Listing API keys", user_id=user_id, account_id=str(account_id)) api_keys = await api_key_service.list_api_keys(account_id) logger.debug( "API keys listed successfully", user_id=user_id, count=len(api_keys) ) return api_keys except HTTPException: raise except Exception as e: logger.error(f"Unexpected error listing API keys: {e}", exc_info=True) raise HTTPException(status_code=500, detail="Failed to list API keys") @router.patch("/api-keys/{key_id}/revoke") async def revoke_api_key( key_id: UUID, user_id: str = Depends(get_current_user_id_from_jwt), api_key_service: APIKeyService = Depends(get_api_key_service), ): """ Revoke an API key Args: key_id: The ID of the API key to revoke user_id: Authenticated user ID from JWT or API key api_key_service: API key service instance Returns: dict: Success message """ try: account_id = await get_account_id_from_user_id(user_id) logger.info( "Revoking API key", user_id=user_id, account_id=str(account_id), key_id=str(key_id), ) success = await api_key_service.revoke_api_key(account_id, key_id) if success: logger.info( "API key revoked successfully", user_id=user_id, key_id=str(key_id) ) return {"message": "API key revoked successfully"} else: raise HTTPException(status_code=500, detail="Failed to revoke API key") except HTTPException: raise except Exception as e: logger.error(f"Unexpected error revoking API key: {e}", exc_info=True) raise HTTPException(status_code=500, detail="Failed to revoke API key") @router.delete("/api-keys/{key_id}") async def delete_api_key( key_id: UUID, user_id: str = Depends(get_current_user_id_from_jwt), api_key_service: APIKeyService = Depends(get_api_key_service), ): """ Permanently delete an API key Args: key_id: The ID of the API key to delete user_id: Authenticated user ID from JWT or API key api_key_service: API key service instance Returns: dict: Success message """ try: account_id = await get_account_id_from_user_id(user_id) logger.info( "Deleting API key", user_id=user_id, account_id=str(account_id), key_id=str(key_id), ) success = await api_key_service.delete_api_key(account_id, key_id) if success: logger.info( "API key deleted successfully", user_id=user_id, key_id=str(key_id) ) return {"message": "API key deleted successfully"} else: raise HTTPException(status_code=500, detail="Failed to delete API key") except HTTPException: raise except Exception as e: logger.error(f"Unexpected error deleting API key: {e}", exc_info=True) raise HTTPException(status_code=500, detail="Failed to delete API key")