'use client'; import React, { useState, useCallback } from 'react'; import { Key, Globe, Shield, XCircle, X } from 'lucide-react'; import type { AuthConfig } from '@mcpengine/ai-pipeline/types'; interface AuthConfigPanelProps { config?: AuthConfig; onChange: (config: AuthConfig | undefined) => void; } type AuthType = 'none' | 'api_key' | 'oauth2' | 'bearer'; const AUTH_OPTIONS: { value: AuthType; label: string; icon: React.ReactNode }[] = [ { value: 'none', label: 'None', icon: }, { value: 'api_key', label: 'API Key', icon: }, { value: 'oauth2', label: 'OAuth2', icon: }, { value: 'bearer', label: 'Bearer', icon: }, ]; export function AuthConfigPanel({ config, onChange }: AuthConfigPanelProps) { const currentType: AuthType = (['api_key', 'oauth2', 'bearer'].includes(config?.type ?? '') ? config!.type : 'none') as AuthType; const [keyName, setKeyName] = useState(config?.keyName ?? ''); const [keyLocation, setKeyLocation] = useState<'header' | 'query'>( config?.keyLocation ?? 'header' ); const [authUrl, setAuthUrl] = useState(config?.oauthConfig?.authUrl ?? ''); const [tokenUrl, setTokenUrl] = useState(config?.oauthConfig?.tokenUrl ?? ''); const [scopes, setScopes] = useState(config?.oauthConfig?.scopes ?? []); const [scopeInput, setScopeInput] = useState(''); const [bearerInstructions, setBearerInstructions] = useState(''); const selectType = useCallback( (type: AuthType) => { if (type === 'none') { onChange(undefined); return; } const base: AuthConfig = { type }; if (type === 'api_key') { base.keyName = keyName; base.keyLocation = keyLocation; } else if (type === 'oauth2') { base.oauthConfig = { authUrl, tokenUrl, scopes }; } onChange(base); }, [onChange, keyName, keyLocation, authUrl, tokenUrl, scopes] ); const addScope = useCallback(() => { const trimmed = scopeInput.trim(); if (trimmed && !scopes.includes(trimmed)) { const newScopes = [...scopes, trimmed]; setScopes(newScopes); setScopeInput(''); onChange({ type: 'oauth2', oauthConfig: { authUrl, tokenUrl, scopes: newScopes }, }); } }, [scopeInput, scopes, onChange, authUrl, tokenUrl]); const removeScope = useCallback( (scope: string) => { const newScopes = scopes.filter((s) => s !== scope); setScopes(newScopes); onChange({ type: 'oauth2', oauthConfig: { authUrl, tokenUrl, scopes: newScopes }, }); }, [scopes, onChange, authUrl, tokenUrl] ); return (
{/* Auth type radio buttons */}
{AUTH_OPTIONS.map((opt) => ( ))}
{/* API Key config */} {currentType === 'api_key' && (
{ setKeyName(e.target.value); onChange({ type: 'api_key', keyName: e.target.value, keyLocation, }); }} placeholder="e.g. X-API-Key" className="w-full bg-gray-800 border border-gray-700 rounded px-2 py-1.5 text-xs text-gray-300 outline-none focus:border-indigo-500 transition-colors" />
)} {/* OAuth2 config */} {currentType === 'oauth2' && (
{ setAuthUrl(e.target.value); onChange({ type: 'oauth2', oauthConfig: { authUrl: e.target.value, tokenUrl, scopes }, }); }} placeholder="https://provider.com/oauth/authorize" className="w-full bg-gray-800 border border-gray-700 rounded px-2 py-1.5 text-xs text-gray-300 outline-none focus:border-indigo-500 transition-colors" />
{ setTokenUrl(e.target.value); onChange({ type: 'oauth2', oauthConfig: { authUrl, tokenUrl: e.target.value, scopes }, }); }} placeholder="https://provider.com/oauth/token" className="w-full bg-gray-800 border border-gray-700 rounded px-2 py-1.5 text-xs text-gray-300 outline-none focus:border-indigo-500 transition-colors" />
{scopes.map((scope) => ( {scope} ))}
setScopeInput(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && addScope()} placeholder="Add scope..." className="flex-1 bg-gray-800 border border-gray-700 rounded px-2 py-1.5 text-xs text-gray-300 outline-none focus:border-indigo-500 transition-colors" />
)} {/* Bearer config */} {currentType === 'bearer' && (