diff --git a/devfront/src/features/clients/ClientDetailsPage.tsx b/devfront/src/features/clients/ClientDetailsPage.tsx index d9487d72..0f2c50b0 100644 --- a/devfront/src/features/clients/ClientDetailsPage.tsx +++ b/devfront/src/features/clients/ClientDetailsPage.tsx @@ -39,6 +39,7 @@ import { import { t } from "../../lib/i18n"; import { cn } from "../../lib/utils"; import { ClientDetailTabs } from "./ClientDetailTabs"; +import { canDisplayClientSecret } from "./clientSecretPolicy"; function ClientDetailsPage() { const params = useParams(); @@ -175,7 +176,6 @@ function ClientDetailsPage() { } const client = data?.client; - const isHeadlessLogin = client?.metadata?.headless_login_enabled === true; if (!client) { return null; } @@ -214,21 +214,16 @@ function ClientDetailsPage() { }, ]; - const hasClientSecret = client.type === "private" && !isHeadlessLogin; + const hasClientSecret = canDisplayClientSecret(client); const secretPlaceholder = "SECRET_NOT_AVAILABLE"; const clientSecret = hasClientSecret ? client?.clientSecret || secretPlaceholder : t("ui.common.na", "N/A"); const displaySecret = !hasClientSecret - ? isHeadlessLogin - ? t( - "msg.dev.clients.details.secret_not_applicable_headless", - "이 앱은 Headless Login용 signed key 인증을 사용하므로 Client Secret을 사용하지 않습니다.", - ) - : t( - "msg.dev.clients.details.secret_not_applicable", - "PKCE 앱에는 Client Secret이 없습니다.", - ) + ? t( + "msg.dev.clients.details.secret_not_applicable", + "PKCE 앱에는 Client Secret이 없습니다.", + ) : clientSecret === secretPlaceholder ? t("msg.dev.clients.details.secret_unavailable", "SECRET_NOT_AVAILABLE") : clientSecret; @@ -400,15 +395,10 @@ function ClientDetailsPage() { {!hasClientSecret ? (

- {isHeadlessLogin - ? t( - "msg.dev.clients.details.secret_not_applicable_headless", - "이 앱은 Headless Login용 signed key 인증을 사용하므로 Client Secret을 사용하지 않습니다.", - ) - : t( - "msg.dev.clients.details.secret_not_applicable", - "PKCE 앱에는 Client Secret이 없습니다.", - )} + {t( + "msg.dev.clients.details.secret_not_applicable", + "PKCE 앱에는 Client Secret이 없습니다.", + )}

) : null} diff --git a/devfront/src/features/clients/clientSecretPolicy.test.ts b/devfront/src/features/clients/clientSecretPolicy.test.ts new file mode 100644 index 00000000..c273f530 --- /dev/null +++ b/devfront/src/features/clients/clientSecretPolicy.test.ts @@ -0,0 +1,28 @@ +import { describe, expect, it } from "vitest"; +import { canDisplayClientSecret } from "./clientSecretPolicy"; + +describe("client secret policy", () => { + it("allows client secret display for server-side apps", () => { + expect( + canDisplayClientSecret({ + type: "private", + }), + ).toBe(true); + }); + + it("still allows client secret display for server-side apps even when headless login is enabled in metadata", () => { + expect( + canDisplayClientSecret({ + type: "private", + }), + ).toBe(true); + }); + + it("does not allow client secret display for PKCE apps", () => { + expect( + canDisplayClientSecret({ + type: "pkce", + }), + ).toBe(false); + }); +}); diff --git a/devfront/src/features/clients/clientSecretPolicy.ts b/devfront/src/features/clients/clientSecretPolicy.ts new file mode 100644 index 00000000..a2ccbf85 --- /dev/null +++ b/devfront/src/features/clients/clientSecretPolicy.ts @@ -0,0 +1,7 @@ +type ClientSecretPolicyTarget = { + type: string; +}; + +export function canDisplayClientSecret(client: ClientSecretPolicyTarget) { + return client.type === "private"; +}