/** * API Key Management Component * Provides interface for creating, viewing, and managing API keys */ import React, { useState, useEffect } from 'react'; import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Alert, AlertDescription } from '@/components/ui/alert'; import { Badge } from '@/components/ui/badge'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Checkbox } from '@/components/ui/checkbox'; import { Key, Plus, Copy, Eye, EyeOff, Trash2, CheckCircle, AlertCircle, Calendar, Shield } from 'lucide-react'; import { useAuthenticatedFetch } from '../../contexts/AuthContext'; interface APIKey { id: number; name: string; key_prefix: string; scopes: string[]; is_active: boolean; last_used?: string; created_at: string; expires_at?: string; } interface CreateAPIKeyRequest { name: string; scopes: string[]; expires_days?: number; } interface CreateAPIKeyResponse { api_key: APIKey; plain_key: string; } const API_SCOPES = [ { id: 'read', label: 'Read Access', description: 'View data and resources' }, { id: 'write', label: 'Write Access', description: 'Create and modify resources' }, { id: 'admin', label: 'Admin Access', description: 'Full administrative access' }, { id: 'agents', label: 'Agent Management', description: 'Manage AI agents' }, { id: 'workflows', label: 'Workflow Management', description: 'Create and run workflows' }, { id: 'monitoring', label: 'Monitoring', description: 'Access monitoring and metrics' } ]; export const APIKeyManager: React.FC = () => { const [apiKeys, setApiKeys] = useState([]); const [isLoading, setIsLoading] = useState(true); const [error, setError] = useState(''); const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false); const [newKey, setNewKey] = useState(null); const [showNewKey, setShowNewKey] = useState(false); const [copiedKeyId, setCopiedKeyId] = useState(null); // Create form state const [createForm, setCreateForm] = useState({ name: '', scopes: [] as string[], expires_days: undefined as number | undefined }); const authenticatedFetch = useAuthenticatedFetch(); useEffect(() => { loadAPIKeys(); }, []); const loadAPIKeys = async () => { try { setIsLoading(true); const response = await authenticatedFetch('/api/auth/api-keys'); if (response.ok) { const keys = await response.json(); setApiKeys(keys); } else { setError('Failed to load API keys'); } } catch (err: any) { setError(err.message || 'Failed to load API keys'); } finally { setIsLoading(false); } }; const handleCreateAPIKey = async () => { try { const requestData: CreateAPIKeyRequest = { name: createForm.name, scopes: createForm.scopes, ...(createForm.expires_days && { expires_days: createForm.expires_days }) }; const response = await authenticatedFetch('/api/auth/api-keys', { method: 'POST', body: JSON.stringify(requestData) }); if (response.ok) { const data: CreateAPIKeyResponse = await response.json(); setNewKey(data.plain_key); setApiKeys(prev => [...prev, data.api_key]); // Reset form setCreateForm({ name: '', scopes: [], expires_days: undefined }); setError(''); } else { const errorData = await response.json(); setError(errorData.detail || 'Failed to create API key'); } } catch (err: any) { setError(err.message || 'Failed to create API key'); } }; const handleDeleteAPIKey = async (keyId: number, keyName: string) => { if (!confirm(`Are you sure you want to delete the API key "${keyName}"? This action cannot be undone.`)) { return; } try { const response = await authenticatedFetch(`/api/auth/api-keys/${keyId}`, { method: 'DELETE' }); if (response.ok) { setApiKeys(prev => prev.filter(key => key.id !== keyId)); } else { setError('Failed to delete API key'); } } catch (err: any) { setError(err.message || 'Failed to delete API key'); } }; const handleToggleAPIKey = async (keyId: number, isActive: boolean) => { try { const response = await authenticatedFetch(`/api/auth/api-keys/${keyId}/toggle`, { method: 'PATCH' }); if (response.ok) { const updatedKey = await response.json(); setApiKeys(prev => prev.map(key => key.id === keyId ? updatedKey : key)); } else { setError('Failed to update API key status'); } } catch (err: any) { setError(err.message || 'Failed to update API key status'); } }; const copyToClipboard = (text: string, keyId?: number) => { navigator.clipboard.writeText(text); if (keyId) { setCopiedKeyId(keyId); setTimeout(() => setCopiedKeyId(null), 2000); } }; const handleScopeChange = (scope: string, checked: boolean) => { setCreateForm(prev => ({ ...prev, scopes: checked ? [...prev.scopes, scope] : prev.scopes.filter(s => s !== scope) })); }; const formatDate = (dateString: string) => { return new Date(dateString).toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }); }; if (isLoading) { return (
); } return (

API Keys

Manage API keys for programmatic access to Hive

Create New API Key
setCreateForm(prev => ({ ...prev, name: e.target.value }))} placeholder="e.g., Production API Key" className="mt-1" />
{API_SCOPES.map(scope => (
handleScopeChange(scope.id, !!checked)} />

{scope.description}

))}
{error && ( {error} )} {newKey && (

API Key Created Successfully!

Please copy your API key now. You won't be able to see it again.

{showNewKey ? newKey : '•'.repeat(40)}
)}
{apiKeys.length === 0 ? (

No API Keys

Create your first API key to start using the Hive API programmatically.

) : ( apiKeys.map(apiKey => (

{apiKey.name}

{apiKey.is_active ? "Active" : "Disabled"}
Key: {apiKey.key_prefix}...
Created: {formatDate(apiKey.created_at)}
{apiKey.last_used && (
Last used: {formatDate(apiKey.last_used)}
)}
{apiKey.expires_at && (
Expires: {formatDate(apiKey.expires_at)}
)}
Scopes:
{apiKey.scopes.map(scope => ( {scope} ))}
)) )}
); }; export default APIKeyManager;