import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import type { AxiosError } from "axios"; import { AlertCircle, Copy, Eye, Link2, Shield, Workflow, Save } from "lucide-react"; import { Link, useParams } from "react-router-dom"; import { Badge } from "../../components/ui/badge"; import { Button } from "../../components/ui/button"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "../../components/ui/card"; import { Separator } from "../../components/ui/separator"; import { Table, TableBody, TableCell, TableRow, } from "../../components/ui/table"; import { Textarea } from "../../components/ui/textarea"; import { Label } from "../../components/ui/label"; import { fetchClient, updateClient } from "../../lib/devApi"; import { useState, useEffect } from "react"; function ClientDetailsPage() { const params = useParams(); const queryClient = useQueryClient(); const clientId = params.id ?? ""; const { data, isLoading, error } = useQuery({ queryKey: ["client", clientId], queryFn: () => fetchClient(clientId), enabled: clientId.length > 0, }); const [redirectUris, setRedirectUris] = useState(""); useEffect(() => { if (data?.client?.redirectUris) { setRedirectUris(data.client.redirectUris.join(", ")); } }, [data]); const mutation = useMutation({ mutationFn: () => { const uriList = redirectUris .split(",") .map((u) => u.trim()) .filter(Boolean); return updateClient(clientId, { redirectUris: uriList }); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["client", clientId] }); alert("Redirect URIs가 저장되었습니다."); }, onError: (err) => { alert(`저장 실패: ${(err as Error).message}`); }, }); if (!clientId) { return
OIDC 자격 증명과 엔드포인트를 관리합니다.
Client ID
{data.client.id}
Client Secret
••••••••••••••••
보안 메모
엔드포인트는 읽기 전용으로 유지하고, 비밀키 재발행/복사는 감사 로그와 연계하세요.
비밀키 재발행 작업에는 관리자 세션 TTL 확인과 레이트리밋, 알림 연동을 권장합니다.