mirror of https://github.com/kortix-ai/suna.git
227 lines
6.7 KiB
Python
227 lines
6.7 KiB
Python
"""
|
|
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")
|