1
0
forked from baron/baron-sso

클라이언트 상세 페이지 비밀키 재발급 기능 연동

This commit is contained in:
2026-02-06 16:16:21 +09:00
parent a443ab3e72
commit b0899d8db3
2 changed files with 36 additions and 5 deletions

View File

@@ -1,7 +1,7 @@
import React, { useState, useEffect } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import type { AxiosError } from "axios";
import { AlertCircle, Copy, Eye, EyeOff, Link2, Shield, Workflow, Save } from "lucide-react";
import { AlertCircle, Copy, Eye, EyeOff, Link2, Shield, Workflow, Save, RefreshCw } from "lucide-react";
import { Link, useParams } from "react-router-dom";
import { Badge } from "../../components/ui/badge";
import { Button } from "../../components/ui/button";
@@ -15,7 +15,7 @@ import {
} from "../../components/ui/table";
import { Textarea } from "../../components/ui/textarea";
import { Label } from "../../components/ui/label";
import { fetchClient, updateClient } from "../../lib/devApi";
import { fetchClient, updateClient, rotateClientSecret } from "../../lib/devApi";
import { cn } from "../../lib/utils";
import { CopyButton } from "../../components/ui/copy-button";
import { toast } from "../../components/ui/use-toast";
@@ -57,6 +57,24 @@ function ClientDetailsPage() {
},
});
const rotateMutation = useMutation({
mutationFn: () => rotateClientSecret(clientId),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["client", clientId] });
toast("Client Secret이 재발급되었습니다.");
setShowSecret(true); // 재발급 후 바로 보여줌
},
onError: (err) => {
toast(`재발급 실패: ${(err as Error).message}`, "error");
},
});
const handleRotateSecret = () => {
if (window.confirm("경고: Client Secret을 재발급하면 기존 시크릿은 즉시 무효화됩니다.\n연동된 애플리케이션이 중단될 수 있습니다. 계속하시겠습니까?")) {
rotateMutation.mutate();
}
};
if (!clientId) {
return <div className="p-8 text-center">Client ID가 .</div>;
}
@@ -176,14 +194,20 @@ function ClientDetailsPage() {
>
{showSecret ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
</Button>
<Button
variant="secondary"
size="icon"
onClick={handleRotateSecret}
disabled={rotateMutation.isPending}
title="비밀키 재발급 (Rotate)"
>
<RefreshCw className={cn("h-4 w-4", rotateMutation.isPending && "animate-spin")} />
</Button>
<CopyButton
value={clientSecret}
disabled={!showSecret && clientSecret === "SECRET_NOT_AVAILABLE"}
onCopy={() => toast("Client Secret이 복사되었습니다.")}
/>
<Button variant="outline" size="icon" className="border-amber-500/50 text-amber-500">
<AlertCircle className="h-4 w-4" />
</Button>
</div>
</div>
</div>

View File

@@ -136,6 +136,13 @@ export async function updateClient(
return data;
}
export async function rotateClientSecret(clientId: string) {
const { data } = await apiClient.post<ClientDetailResponse>(
`/dev/clients/${clientId}/secret/rotate`
);
return data;
}
export async function deleteClient(clientId: string) {
await apiClient.delete(`/dev/clients/${clientId}`);
}